1043. This Takes the Cake
Constraints
Time Limit: 1 secs, Memory Limit: 32 MB
Description
In the kingdom of Polygonia the royal family consists of the king, the queen, and the 10-year-old twins, Prince Obtuse and Prince Trisect. The twins are fiercely competitive, and on their birthday they always vie with each other for the biggest portion of the cake. The wise king and queen have devised the following way to prevent squabbles over the cake. One prince is allowed to cut the cake into two pieces, then the other prince gets to choose which of the two pieces he wants.
Cakes in Polygonia are always in the shape of a convex quadrilateral (a four-sided polygon with each internal angle less than 180 degrees). Furthermore, local custom dictates that all cake cutting must be done using a straight cut that joins two vertices, or two midpoints of the sides of the cake, or a vertex and a midpoint. For instance, the following figure shows all the possible legal cuts in a typical cake.
Your problem is to determine, for a number of different cakes, the best cut, i.e., the one that divides the cake into two pieces whose areas (we are disregarding the thickness of the cake) are as nearly equal as possible. For instance, given a cake whose vertices (when the cake is viewed from above) are located, in counterclockwise order, at the points (0, 1), (6, 0), (5, 2) and (2, 3), the best possible cut would divide the cake into two pieces, one with area 4.375, the other with area 5.125; the cut joins the points (1, 2) and (5:5, 1) (the midpoints of two of the sides).
Input
Input consists of a sequence of test cases, each consisting of four (x; y) values giving the counterclockwise traversal of the cake's vertices as viewed from directly above the cake; the final test case is followed by a line containing eight zeros. No three points will be collinear, all quadrilaterals are convex, and all coordinates will have absolute values of 10000 or less.
Output
For each cake, the cake number followed by the two areas, smaller first, to three decimal places of precision.
Sample Input
0 1 6 0 5 2 2 3 0 0 100 0 100 100 0 100 0 0 0 0 0 0 0 0
Sample Output
Cake 1: 4.375 5.125Cake 2: 5000.000 5000.000
这题就是遍历所有的切割情况,找出两块面积之差最小的一种。貌似这题很容易在精度上出问题,明明在逻辑上等价的改动结果一个AC一个WA。
// Problem#: 1043 // Submission#: 5065931 // The source code is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License // URI: http://creativecommons.org/licenses/by-nc-sa/3.0/ // All Copyright reserved by Informatic Lab of Sun Yat-sen University #include<iostream> #include<iomanip> #include<cstring> #include<cmath> using namespace std; struct point{//保存每个点的横纵坐标 double x,y; point(){} }; point node[8];//四个顶点四个中点共八个点 double getDis(point A,point B)//计算两个点之间的距离 { return sqrt(pow(A.x-B.x,2)+pow(A.y-B.y,2)); } double get_area_tri(point A,point B,point C)//用海伦公式,由三角形三边长求面积 { double a=getDis(A,B); double b=getDis(A,C); double c=getDis(B,C); double p=(a+b+c)/2.0; double area=sqrt(p*(p-a)*(p-b)*(p-c)); return area; } double polygon(int pos1,int pos2)//求多边形的面积,pos1为多边形起始点在node数组中的下标,pos2为末点在node数组中的下标 { double area=0;//将一个多边形划分成多个以pos1点为顶点的三角形,分别计算三角形面积再累加 if(pos1%2==0)//如果pos1为偶数说明pos1是顶点,那么pos1,(pos1+1)%8和(po1+2)%8共线,不构成三角形,所以从(pos1+2)%8开始计算 { for(int i=(pos1+2)%8;i!=pos2;i=(i+1)%8) { area+=get_area_tri(node[pos1],node[i],node[(i+1)%8]); } } else//否则直接从(pos1+1)%8开始计算即可 { for(int i=(pos1+1)%8;i!=pos2;i=(i+1)%8) { area+=get_area_tri(node[pos1],node[i],node[(i+1)%8]); } } return area; } int main() { int count=1; while(1) { //node数组中第一个点为顶点,然后按照逆时针顺序中点顶点交替 cin>>node[0].x>>node[0].y>>node[2].x>>node[2].y>>node[4].x>>node[4].y>>node[6].x>>node[6].y; if(node[0].x==0&&node[0].y==0&&node[2].x==0&&node[2].y==0&& node[4].x==0&&node[4].y==0&& node[6].x==0&&node[6].y==0) break; for(int i=1;i<=7;i+=2) { node[i].x=(node[i-1].x+node[(i+1)%8].x)/2.0;//注意取余 node[i].y=(node[i-1].y+node[(i+1)%8].y)/2.0; } double total_area=polygon(0,6);//计算总面积 double half=total_area/2.0;//四边形半面积,要使两部分面积之差最小,则要使四边形半面积与两部分图形中的一个面积之差最小 double gap=200000000;//面积差先设为一个很大的数,至少要大于fabs(half-area)的最大值,由于四边形的最大面积4e8,所以将gap初始化为2e8 for(int i=0;i<8;++i)//从一个点开始遍历以这一点为切割点之一的所有切割方法,这样虽然代码简便但会有重复运算 { int j; if(i%2==0)//若这一点是顶点 { j=(i+3)%8;//则从这一点的逆时针序后3点开始作为另一个切割点 while((j+2)%8!=i)//终止条件 { if(fabs(half-polygon(i,j))<gap)//如果找到了更小的gap值则更新它 { gap=fabs(half-polygon(i,j)); } j=(j+1)%8; } } else// 若这一点是中点 { j=(i+2)%8;//则可以从这一点的逆时针序后2点开始作为另一个切割点 while((j+1)%8!=i) { if(fabs(half-polygon(i,j))<gap) { gap=fabs(half-polygon(i,j)); } j=(j+1)%8; } } } cout<<fixed<<setprecision(3)<<"Cake "<<count++<<": "<<half-gap<<" "<<half+gap<<endl;//保留三位小数输出 } return 0; }