1. 程式人生 > >Gym 101873G - Water Testing - [皮克定理]

Gym 101873G - Water Testing - [皮克定理]

端點 連接 pro i+1 sca arr ref div 邊界

題目鏈接:http://codeforces.com/gym/101873/problem/G

題意:

在點陣上,給出 $N$ 個點的坐標(全部都是在格點上),將它們按順序連接可以構成一個多邊形,求該多邊形內包含的格點的數目。

題解:

首先,根據皮克定理 $S = a + \frac{b}{2} - 1$,其中 $S$ 是多邊形面積,$a$ 是多邊形內部格點數目,$b$ 是多邊形邊界上的格點數目。

那麽,我們只要求出 $S$ 和 $b$,就很好求得 $a$ 了:

1、對於兩端點 $(x_1,y_1),(x_2,y_2)$ 都再格點上的一條線段,該線段上的格點數目為 $\gcd(|x_1-x_2|,|y_1-y_2|)+1$。這很好理解,對於橫坐標差值和縱坐標差值求得的最大公因數 $g$,相當於將橫坐標差值分成 $g$ 份,由於是整除,因此顯然每份的左右端點都是整數,對於縱坐標也是同樣的道理,由於是最大公因數,所以不可能再分更多份,因此 $\gcd(|x_1-x_2|,|y_1-y_2|)$ 即求得兩端點間最多能分成多少段由格點分割的線段,再加上 $1$ 即整條線段上的格點數目。

2、對於格點按順序給出的多邊形,設 $P_0 = P_{n+1}$ 且 $O$ 為原點,則面積為 $\frac{1}{2} \sum_{i=0}^{n}{\left ( \overrightarrow{OP_i} \times \overrightarrow{OP_{i+1}} \right )}$。這個畫個圖模擬一下也非常容易理解。

AC代碼:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pll;
const int maxn=1e5+10
; int n; pll p[maxn]; inline ll gcd(ll m,ll n){return n?gcd(n,m%n):m;} int main() { cin>>n; for(int i=0;i<n;i++) scanf("%lld%lld",&p[i].first,&p[i].second); ll S2=0, b=0; for(int i=0;i<n;i++) { S2+=p[i].first*p[(i+1)%n].second-p[i].second*p[(i+1)%n].first; b
+=gcd(abs(p[i].first-p[(i+1)%n].first),abs(p[i].second-p[(i+1)%n].second)); } cout<<(abs(S2)-b+2)/2<<endl; }

Gym 101873G - Water Testing - [皮克定理]