1. 程式人生 > >poj 2954 Triangle (pick定理應用)

poj 2954 Triangle (pick定理應用)

題目連結:bang

題意:給你三個點,每個點的座標都是整數,問這個三角形內部有多少個整數點?

 

題解:pick定理解決,至於證明pick定理的,這有一篇強行解釋的:

http://blog.sina.com.cn/s/blog_a1c409e30101efme.html

再來一篇強行解釋的:

http://www.matrix67.com/blog/archives/768

參考連結:

 

https://blog.csdn.net/u013480600/article/details/39269265?utm_source=blogxgwz4

這篇部落格證明邊上有多少個整數點證明得很好。這裡就直接不加修飾的搬了。

Pick定理,一個多邊形如果每個頂點都由整點構成,該多邊形的面積為S,該多邊形邊上整點為L,內部整點為N,則有:

       N+L/2-1=S.

       那麼我們只要求出該三角形的面積和三角形邊上到底有多少個整點即可. 面積直接用叉積求.下面求三角形各邊上有多少個整點.

       假設有一條由兩個整點構成的線段,該線段該線段X方向的增量絕對值為DX, Y方向的增量絕對值為DY. 設線段內部(不含端點

)整點個數為ans:

       DX==DY==0時, ans=0

       DX==0時, ans=DY-1(等價於gcd(DX,DY)-1 )

       DY==0時, ans=DX-1 (等價於gcd(DX,DY)-1 )

       DX!=0DY!=0時, ans=gcd(DX,DY)-1

       簡單說明一下上面結論:

       端點是整點的線段內部如果有整點, 那線段一定是被內部的整點均勻分割的.

假設線段內部有5個整點(這5個整點一定是均勻排列的),那麼包括兩端點共7個整點,線段被分成了6等份. 其實就是DX和DY分別被分成了6等份,那麼說明DX和DY的最大公約數==6. 如果DX與DY的最大公約數==8,那麼線段一定且最多能被分成8等份,且由於線段端點是整點,所以8等份的每個點都是整點.
 

///pick定理 面積=內部隔點數+邊上隔點數/2-1

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>

using namespace std;

struct point{
    int x,y;
    point(){}
    point(int _x,int _y){
        x=_x;y=_y;
    }
}p[5];

point operator + (point a,point b) {return point(a.x+b.x,a.y+b.y);}
point operator - (point a,point b) {return point(a.x-b.x,a.y-b.y);}
point operator * (point a,int p) { return point(a.x*p,a.y*p);}
point operator / (point a,int p){ return point(a.x/p,a.y/p);}

bool operator < (const point &a,const point &b){
    return a.x<b.x||(a.x==b.x&&a.y<b.y);
}
const double esp=1e-8;
int dcmp(double x){
    if(fabs(x)<esp) return 0;
    else return x<0?-1:1;
}
bool operator ==(const point &a,const point &b){
    return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;
}


int Cross(point a,point b) { return fabs(a.x*b.y-a.y*b.x);}

int gcd(int a,int b){
    if(!b) return a;
    else return gcd(b,a%b);
}

int solve(point a,point b){ ///求解ab邊上不包括端點的整點個數
    int dx=fabs(a.x-b.x),dy=fabs(a.y-b.y);

    if(dx==0&&dy==0) return 0;
    return gcd(dx,dy)-1;
}

int main()
{
    int x1,x2,x3,y1,y2,y3;

    while(~scanf("%d%d%d%d%d%d",&x1,&y1,&x2,&y2,&x3,&y3))
    {
        if(x1==0&&x2==0&&x3==0&&y1==0&&y2==0&&y3==0) break;

        p[0]=point(x1,y1);
        p[1]=point(x2,y2);
        p[2]=point(x3,y3);

        int area=Cross(p[1]-p[0],p[2]-p[0])/2; ///叉積求面積

        int edgenode=3+solve(p[0],p[1])+solve(p[0],p[2])+solve(p[1],p[2]);

        printf("%d\n",area+1-edgenode/2); ///pick定理


    }
    return 0;
}