向量叉积的运用
题解报告:hdu 2036 改革春风吹满地 (求多边形的面积)
Problem Description
“ 改革春风吹满地,
不会AC没关系;
实在不行回老家,
还有一亩三分地。
谢谢!(乐队奏乐)”
话说部分学生心态极好,每天就知道游戏,这次考试如此简单的题目,也是云里雾里,而且,还竟然来这么几句打油诗。
好呀,老师的责任就是帮你解决问题,既然想种田,那就分你一块。
这块田位于浙江省温州市苍南县灵溪镇林家铺子村,多边形形状的一块地,原本是linle 的,现在就准备送给你了。不过,任何事情都没有那么简单,你必须首先告诉我这块地到底有多少面积,如果回答正确才能真正得到这块地。
发愁了吧?就是要让你知道,种地也是需要AC知识的!以后还是好好练吧...
不会AC没关系;
实在不行回老家,
还有一亩三分地。
谢谢!(乐队奏乐)”
话说部分学生心态极好,每天就知道游戏,这次考试如此简单的题目,也是云里雾里,而且,还竟然来这么几句打油诗。
好呀,老师的责任就是帮你解决问题,既然想种田,那就分你一块。
这块田位于浙江省温州市苍南县灵溪镇林家铺子村,多边形形状的一块地,原本是linle 的,现在就准备送给你了。不过,任何事情都没有那么简单,你必须首先告诉我这块地到底有多少面积,如果回答正确才能真正得到这块地。
发愁了吧?就是要让你知道,种地也是需要AC知识的!以后还是好好练吧...
Input
输入数据包含多个测试实例,每个测试实例占一行,每行的开始是一个整数n(3<=n<=100),它表示多边形的边数(当然也是顶点数),然后是按照逆时针顺序给出的n个顶点的坐标(x1, y1, x2, y2... xn, yn),为了简化问题,这里的所有坐标都用整数表示。
输入数据中所有的整数都在32位整数范围内,n=0表示数据的结束,不做处理。
输入数据中所有的整数都在32位整数范围内,n=0表示数据的结束,不做处理。
Output
对于每个测试实例,请输出对应的多边形面积,结果精确到小数点后一位小数。
每个实例的输出占一行。
每个实例的输出占一行。
Sample Input
3 0 0 1 0 0 1
4 1 0 0 1 -1 0 0 -1
0
Sample Output
0.5
2.0
解题思路:由于此题输入是按逆时针顺序给出n个坐标点,因此将第一个坐标点作为基点,与其不相邻的(n-3)个顶点一一进行连线,则多边形被分割成(n-2)个三角形,而每个三角形的面积可以表示为由两个向量叉积的一半即p0p1(向量)×p0p2(向量)/2,为避免产生的误差,这里先对所有叉积结果累加,最后再除以2即可得到多边形的面积。
AC代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 struct node{int x,y;}nod[105]; 4 inline int cross(node p0,node p1,node p2){//叉积 5 return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y); 6 } 7 int main(){ 8 int n;double sum; 9 while(cin>>n&&n){ 10 for(int i=0;i<n;++i) 11 cin>>nod[i].x>>nod[i].y; 12 sum=0; 13 for(int i=2;i<n;++i) 14 sum+=cross(nod[0],nod[i-1],nod[i]); 15 cout<<setiosflags(ios::fixed)<<setprecision(1)<<(sum/2)<<endl; 16 } 17 return 0; 18 }
题解报告:NYOJ #68 三点顺序
描述
现在给你不共线的三个点A,B,C的坐标,它们一定能组成一个三角形,现在让你判断A,B,C是顺时针给出的还是逆时针给出的?
如:
图1:顺时针给出
图2:逆时针给出
<图1> <图2>
输入
每行是一组测试数据,有6个整数x1,y1,x2,y2,x3,y3分别表示A,B,C三个点的横纵坐标。(坐标值都在0到10000之间)
输入0 0 0 0 0 0表示输入结束
输入0 0 0 0 0 0表示输入结束
测试数据不超过10000组输出如果这三个点是顺时针给出的,请输出1,逆时针给出则输出0
样例输入
0 0 1 1 1 3 0 1 1 0 0 0 0 0 0 0 0 0样例输出
0 1解题思路:看图就明白了。
AC代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 struct node{int x,y;}nod[5]; 4 inline int cross(node p0,node p1,node p2){//叉积 5 return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y); 6 } 7 int main(){ 8 while(cin>>nod[0].x>>nod[0].y>>nod[1].x>>nod[1].y>>nod[2].x>>nod[2].y){ 9 int sum=0; 10 for(int i=0;i<3;++i)sum+=(nod[i].x+nod[i].y); 11 if(!sum)break; 12 if(cross(nod[0],nod[1],nod[2])<0)cout<<1<<endl;//顺时针 13 else cout<<0<<endl;//逆时针 14 } 15 return 0; 16 }
题解报告:NYOJ #67 三角形面积
描述
给你三个点,表示一个三角形的三个顶点,现你的任务是求出该三角形的面积。
输入
每行是一组测试数据,有6个整数x1,y1,x2,y2,x3,y3分别表示三个点的横纵坐标。(坐标值都在0到10000之间)
输入0 0 0 0 0 0表示输入结束
测试数据不超过10000组
输出
输出这三个点所代表的三角形的面积,结果精确到小数点后1位(即使是整数也要输出一位小数位)
样例输入
0 0 1 1 1 3 0 1 1 0 0 0 0 0 0 0 0 0
样例输出
1.0 0.5
解题思路:两向量进行叉乘,简单运用。
AC代码:
1 #include<stdio.h> 2 #include<math.h> 3 int main(){ 4 int x1,y1,x2,y2,x3,y3; 5 while(~scanf("%d%d%d%d%d%d",&x1,&y1,&x2,&y2,&x3,&y3)&&(x1+y1+x2+y2+x3+y3)){ 6 printf("%.1f\n",fabs((x2-x1)*(y3-y1)-(x3-x1)*(y2-y1))*0.5); 7 } 8 return 0; 9 }
题解报告:hdu 1115 Lifting the Stone(求多边形的重心)
Problem Description
There are many secret openings in the floor which are covered by a big heavy stone. When the stone is lifted up, a special mechanism detects this and activates poisoned arrows that are shot near the opening. The only possibility is to lift the stone very slowly and carefully. The ACM team must connect a rope to the stone and then lift it using a pulley. Moreover, the stone must be lifted all at once; no side can rise before another. So it is very important to find the centre of gravity and connect the rope exactly to that point. The stone has a polygonal shape and its height is the same throughout the whole polygonal area. Your task is to find the centre of gravity for the given polygon.
Input
The input consists of T test cases. The number of them (T) is given on the first line of the input file. Each test case begins with a line containing a single integer N (3 <= N <= 1000000) indicating the number of points that form the polygon. This is followed by N lines, each containing two integers Xi and Yi (|Xi|, |Yi| <= 20000). These numbers are the coordinates of the i-th point. When we connect the points in the given order, we get a polygon. You may assume that the edges never touch each other (except the neighboring ones) and that they never cross. The area of the polygon is never zero, i.e. it cannot collapse into a single line.
Output
Print exactly one line for each test case. The line should contain exactly two numbers separated by one space. These numbers are the coordinates of the centre of gravity. Round the coordinates to the nearest number with exactly two digits after the decimal point (0.005 rounds up to 0.01). Note that the centre of gravity may be outside the polygon, if its shape is not convex. If there is such a case in the input data, print the centre anyway.
Sample Input
2
4
5 0
0 5
-5 0
0 -5
4
1 1
11 1
11 11
1 11
Sample Output
0.00
0.00
6.00
6.00
解题思路:由于此题是按逆时针顺序给出每个点的坐标,因此可以边读边计算。其实在求解的过程中,不需要考虑点的输入顺序是顺时针还是逆时针,累加再相除就抵消负号了。将多边形分割成多个三角形,那么多边形的重心(σ_x,σ_y)就是每个三角形的重心(σ_xi,σ_yi)乘以对应的面积之和再除以多边形的面积即可。
,
AC代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 struct node{double x,y;}p1,p2,p3; 4 int t,n;double sum,sum_x,sum_y; 5 double cross(node p1,node p2,node p3){//两向量的叉乘计算 6 return (p2.x-p1.x)*(p3.y-p1.y)-(p3.x-p1.x)*(p2.y-p1.y); 7 } 8 int main(){ 9 while(~scanf("%d",&t)){ 10 while(t--){ 11 scanf("%d%lf%lf%lf%lf",&n,&p1.x,&p1.y,&p2.x,&p2.y);sum=sum_x=sum_y=0.0; 12 for(int i=3;i<=n;++i){ 13 scanf("%lf%lf",&p3.x,&p3.y); 14 double area=cross(p1,p2,p3); 15 sum+=area; 16 sum_x+=(p1.x+p2.x+p3.x)*area; 17 sum_y+=(p1.y+p2.y+p3.y)*area; 18 p2=p3; 19 } 20 sum_x/=sum,sum_y/=sum; 21 printf("%.2f %.2f\n",sum_x/3,sum_y/3); 22 } 23 } 24 return 0; 25 }
题解报告:NYOJ #3 多边形重心问题
描述
在某个多边形上,取n个点,这n个点顺序给出,按照给出顺序将相邻的点用直线连接, (第一个和最后一个连接),所有线段不和其他线段相交,但是可以重合,可得到一个多边形或一条线段或一个多边形和一个线段的连接后的图形;
如果是一条线段,我们定义面积为0,重心坐标为(0,0).现在求给出的点集组成的图形的面积和重心横纵坐标的和;
如果是一条线段,我们定义面积为0,重心坐标为(0,0).现在求给出的点集组成的图形的面积和重心横纵坐标的和;
输入
第一行有一个整数0<n<11,表示有n组数据;
每组数据第一行有一个整数m<10000,表示有这个多边形有m个顶点;
每组数据第一行有一个整数m<10000,表示有这个多边形有m个顶点;
输出
输出每个多边形的面积、重心横纵坐标的和,小数点后保留三位;
样例输入
3 3 0 1 0 2 0 3 3 1 1 0 0 0 1 4 1 1 0 0 0 0.5 0 1
样例输出
0.000 0.000 0.500 1.000 0.500 1.000
解题思路:此题和上题一样,就是最后应取多边形面积的绝对值,且如果sum<1e-6,说明此时是一条线段,则应单独输出,因为分母不能为0;其余不变,求解过程不需要考虑点的输入顺序是顺时针还是逆时针,直接累加即可。
AC代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 struct node{double x,y;}p1,p2,p3; 4 const double eps=1e-6; 5 int t,n;double sum,sum_x,sum_y; 6 double cross(node p1,node p2,node p3){ 7 return (p2.x-p1.x)*(p3.y-p1.y)-(p3.x-p1.x)*(p2.y-p1.y); 8 } 9 int main(){ 10 while(~scanf("%d",&t)){ 11 while(t--){ 12 scanf("%d%lf%lf%lf%lf",&n,&p1.x,&p1.y,&p2.x,&p2.y);sum=sum_x=sum_y=0.0; 13 for(int i=3;i<=n;++i){ 14 scanf("%lf%lf",&p3.x,&p3.y); 15 double area=cross(p1,p2,p3); 16 sum+=area; 17 sum_x+=(p1.x+p2.x+p3.x)*area; 18 sum_y+=(p1.y+p2.y+p3.y)*area; 19 p2=p3; 20 } 21 double tot=fabs(sum)/2; 22 if(tot<eps)printf("0.000 0.000\n"); 23 else printf("%.3f %.3f\n",tot,(sum_x+sum_y)/sum/3); 24 } 25 } 26 return 0; 27 }