题目:在一个平面坐标系中,我们可以选出三个不全在一条线上的点构成一个三角形。我们称一个在三角形内(不包含三角形的边上),横纵坐标皆为整数的点位这个三角形的内点。 对于一个由(0,0)、(n,m)、(p,0)作为顶点构成的三角形,请你设计程序求出他的内点数。
输入包括一行,包括三个用空格分隔的整数,分别为n,m,p(0 ≤ n < 32000,0 < m < 32000,0 < p < 32000)。
输出仅一个数,为这个三角形的内点的个数。
样例输入
7 5 10
样例输出
20
题意分析:
第一种思路(pick定理):皮克定理是指一个计算点阵中顶点在格点上的多边形面积公式,该公式可以表示为2S=2a+b-2,其中a表示多边形内部的点数,b表示多边形边界上的点数,s表示多边形的面积。在这题中,我们可以发现,如果要利用此公式,还必须知道边界上的整点的数目,我们可以通过gcd(a,b),a和b为直角三角形的两直角边整点数目,来求斜边上的整点数目,然后再计算出结果即可。
第二种思路(模拟):首先对于该题,我们要明确的是它想求的是内点的数量,并且这题比较简单的地方是它固定了一个点,且固定了底边的另一个点的纵坐标。基于这种情况,我们就只需要考虑两种情况,一种是n<=p,另一种是n>p。当n<=p时,直接通过扫描后相加就可以求出点的数量,只不过要注意边界不考虑,以及通过比较虑斜率的大小来判断点再三角形内(用乘法可以避免double的类型的减法)。当n>p时,我们可以考虑是在n,m,n的大直角三角形内点数,减去底下小直角三角形的内点数加上斜边上包含在大直角三角形内点里的内点数。这样就求出了结果。
#include <iostream> #include <list> #include <cstdio> #include <cmath> #include <cstring> #include <fstream> #include <algorithm> #include <queue> #include <vector> #include <string> #include <cstdlib> #include <sstream> using namespace std; int gcd(int a,int b) { return b==0?a:gcd(b,a%b); } int main() { int n,m,p; cin>>n>>m>>p; int s=p*m/2; cout<<s+1-(gcd(n,m)+gcd(fabs(p-n),m)+p)/2<<endl; return 0; }
#include <iostream> #include <list> #include <cstdio> #include <cmath> #include <cstring> #include <fstream> #include <algorithm> #include <queue> #include <vector> #include <string> #include <cstdlib> #include <sstream> using namespace std; int solve(int n,int m,int p) { int sum = 0; int Rx=n+1,Ry=m-1,Lx=n-1,Ly=m-1; while(Lx>0 && Ly>0) { if( (m-Ly)*n > (n-Lx)*m ) { sum+=Ly; Lx--; } else Ly--; } while(Rx<p && Ry>0) { if( Ry*(p-n)<(p-Rx)*m ) { sum+=Ry; Rx++; } else Ry--; } if(n!=0 && n!=p) sum+=m-1; return sum; } int solve2(int n,int m,int p) { int sum=0; int y=m-1,x=n-1; while(y>0 && x>2) { if( y*(n-p)<=m*(x-p) ) { sum+=y; x--; } else y--; } return solve(n,m,n)-sum; } int main() { int n,m,p; cin>>n>>m>>p; if(n<=p) cout<<solve(n,m,p)<<endl; else cout<<solve2(n,m,p)<<endl; return 0; }