You want to hold a party. Here's a polygon-shaped cake on the table. You'd like to cut the cake into several triangle-shaped parts for the invited comers. You have a knife to cut. The trace of each cut is a line segment, whose two endpoints are two vertices of the polygon. Within the polygon, any two cuts ought to be disjoint. Of course, the situation that only the endpoints of two segments intersect is allowed.
The cake's considered as a coordinate system. You have known the coordinates of vexteces. Each cut has a cost related to the coordinate of the vertex, whose formula is costi, j = |xi + xj| * |yi + yj| % p. You want to calculate the minimum cost.
NOTICE: input assures that NO three adjacent vertices on the polygon-shaped cake are in a line. And the cake is not always a convex.
There're multiple cases. There's a blank line between two cases.The first line of each case contains two integers, N and p (3 ≤ N, p ≤ 300), indicating the number of vertices. Each line of the following N lines contains two integers, x and y (-10000 ≤ x, y ≤ 10000), indicating the coordinate of a vertex. You have known that no two vertices are in the same coordinate.
If the cake is not convex polygon-shaped, output "I can't cut.". Otherwise, output the minimum cost.
3 3 0 0 1 1 0 2
0
几乎就是照着敲的,惭愧ing
说题意,想找论文题没找到,只有浙大的这个比较类似,但是有凸包,本宝宝不开心……简单说一下凸包,“在地上放置一些不可移动的木桩,用一根绳子把他们尽量紧地圈起来,并且为凸边形,这就是凸包了”,本题要求所有已知点都在绳子上,不在的输出提示信息。什么情况不在,凸包的算法入栈个数小于点的个数的时候不在。
再说排序之后的处理,根据论文中对于最优三角剖分的处理讲解,我们知道需要确定一个凸多边形,然后找一条边把他分成两半。实际写的时候受前几个题的影响,后面的花费写错了两个地方
dp[i][k]+dp[k][j]+cost[i][k]+cost[k][j] 1.后一个dp也是从k开始 2.cost是两个值,因为算法是在i-j的区间内找到一个过渡点k,连接i-k j-k形成中间三角形和两个凸多边形而成
再有就是注意循环顺序,这个题不用处理环,但是最好是开头定点从大往小枚举
/**************** zoj3537 2016.2.19 C++ 70 8096 ***************/ #include <iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; const int MAXN=1000; struct point { int x,y; }; point list[MAXN]; int stack[MAXN],top; int cross(point p0,point p1,point p2) //计算叉积 p0p1 X p0p2 { return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x); } double dis(point p1,point p2) //计算 p1p2的 距离 { return sqrt((double)(p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y)); } bool cmp(point p1,point p2) //极角排序函数 , 角度相同则距离小的在前面 { int tmp=cross(list[0],p1,p2); if(tmp>0) return true; else if(tmp==0&&dis(list[0],p1)<dis(list[0],p2)) return true; else return false; } void init(int n) //输入,并把 最左下方的点放在 list[0] 。并且进行极角排序 { int i,k; point p0; scanf("%d%d",&list[0].x,&list[0].y); p0.x=list[0].x; p0.y=list[0].y; k=0; for(i=1;i<n;i++) { scanf("%d%d",&list[i].x,&list[i].y); if( (p0.y>list[i].y) || ((p0.y==list[i].y)&&(p0.x>list[i].x)) ) { p0.x=list[i].x; p0.y=list[i].y; k=i; } } list[k]=list[0]; list[0]=p0; sort(list+1,list+n,cmp); } void graham(int n) { int i; if(n==1) {top=0;stack[0]=0;} if(n==2) { top=1; stack[0]=0; stack[1]=1; } if(n>2) { for(i=0;i<=1;i++) stack[i]=i; top=1; for(i=2;i<n;i++) { while(top>0&&cross(list[stack[top-1]],list[stack[top]],list[i])<=0) top--; top++; stack[top]=i;///0~n-1 } } } void print(int n) { for(int i=0;i<n;i++) printf("stack=%d,x=%d,y=%d\n",stack[i],list[stack[i]].x,list[stack[i]].y); } int cost[MAXN][MAXN]; int calc(point p1,point p2,int m)//计算题目定义的cost { return abs(p1.x+p2.x)*abs(p1.y+p2.y)%m; } int dp[MAXN][MAXN]; int main() { freopen("cin.txt","r",stdin); int p,n; while(~scanf("%d%d",&n,&p)) { init(n); graham(n); //print(n); if(top!=n-1) { printf("I can't cut.\n"); continue; } memset(cost,0,sizeof(cost)); for(int i=0;i<n;i++) for(int j=i+2;j<n;j++) cost[j][i]=cost[i][j]=calc(list[i],list[j],p); for(int i=0;i<n;i++) { for(int j=i;j<n;j++) dp[i][j]=0x3f3f3f3f; dp[i][(i+1)%n]=0; } for(int i=n-3;i>=0;i--)//start { for(int j=i+2;j<n;j++)//end { for(int k=i+1;k<j;k++)//mid dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]+cost[i][k]+cost[k][j]); } } // for(int l=2;l<n;l++)//len // { // for(int i=0;i<=n-3;i++)//start // { // int j=i+l; // for(int k=i+2;k<j;k++) // { // dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]+cost[i][k]+cost[k][j]); // } // } // } printf("%d\n",dp[0][n-1]); } return 0; }