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

題目連接:http://codeforces.com/gym/101873/problem/Gc++

 

題意:spa

在點陣上,給出 $N$ 個點的座標(所有都是在格點上),將它們按順序鏈接能夠構成一個多邊形,求該多邊形內包含的格點的數目。code

 

題解:blog

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

那麼,咱們只要求出 $S$ 和 $b$,就很好求得 $a$ 了:get

一、對於兩端點 $(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$ 即整條線段上的格點數目。it

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

 

AC代碼:gc

#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;
}
相關文章
相關標籤/搜索