本文主要是介绍ZOJ 3537,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
原题:
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.
Input
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.
Output
If the cake is not convex polygon-shaped, output “I can’t cut.”. Otherwise, output the minimum cost.
Sample Input
3 3
0 0
1 1
0 2
Sample Output
0
中文:
给你个蛋糕,让你分割。如果蛋糕不是多边形的,不能分。
否则蛋糕分割的时候有权重。蛋糕表现为在二维坐标系上的一个点集合,分割蛋糕需要在蛋糕上的两个点i和j上砍一刀,权重为cost[i, j] = |xi + xj| * |yi + yj| % p
现在问你把蛋糕全部分成三角形,是的最后的权重最小。
代码:
#include <bits/stdc++.h>
#define Vector Pointusing namespace std;const int maxn = 405;
const double eps = 1e-5;struct Point
{int x,y;Point(int x=0,int y=0):x(x),y(y){}
};
bool operator < (const Point &a,const Point &b)//排序用,按照x的坐标从小到大,如果x相同,那么按照y从小到大
{return a.x<b.x||(a.x==b.x&&a.y<b.y);
}Vector operator +(Vector A,Vector B){return Vector(A.x+B.x,A.y+B.y);}//坐标点相加
Vector operator -(Vector A,Vector B){return Vector(A.x-B.x,A.y-B.y);}//相减int Cross(Vector A,Vector B)
{return A.x*B.y-A.y*B.x;
}int ConvexHull(Point *P,int n,Point *ch)//p是所有点,n所有点的个数,ch里面记录形成凸包的点,返回凸包点的个数
{sort(P,P+n);int m=0;for(int i=0;i<n;i++){while(m>1&&Cross(ch[m-1]-ch[m-2],P[i]-ch[m-2])<=0)m--;ch[m++]=P[i];}int k=m;for(int i=n-2;i>=0;i--){while(m>k&&Cross(ch[m-1]-ch[m-2],P[i]-ch[m-2])<=0)m--;ch[m++]=P[i];}if(n>1)m--;return m;
}
int n,p;
Point ps[maxn],tps[maxn];
int cost[maxn][maxn];
int dp[maxn][maxn];
int Cost(int i,int j)
{return (abs(tps[i].x+tps[j].x)*abs(tps[i].y+tps[j].y))%p;
}int main()
{ios::sync_with_stdio(false);while(cin>>n>>p){for(int i=0;i<n;i++)cin>>ps[i].x>>ps[i].y;if(n<=3){cout<<0<<endl;continue;}int m = ConvexHull(ps,n,tps);if(m!=n){cout<<"I can't cut."<<endl;continue;}for(int i=0;i<n;i++){for(int j=i+2;j<n;j++){cost[i][j]=cost[j][i]=Cost(i,j);}}for(int i=0;i<n;i++){for(int j=0;j<n;j++){dp[i][j]=INT_MAX;}}for(int i=0;i<n-1;i++)dp[i][i+1]=0;for(int i = n-3;i>=0;i--){for(int j = i+2;j<n;j++){for(int k=i+1;k<j;k++){dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]+cost[i][k]+cost[k][j]);}}}cout<<dp[0][n-1]<<endl;}return 0;
}
解答:
首先判断给的蛋糕是不是凸包,如果是不是凸包直接输出I can’t cut.
如果是凸包,就要按照要求进行切割。此题算是最优三角剖分的改进,状态方程很容易得到。
此题有个小坑需要注意,也是最优三角剖分需要注意的点,就是进行dp的过程,要求提供的多边形点集一定是沿着一个方向的。
设置 d p [ i ] [ j ] dp[i][j] dp[i][j]表示第i个点到第j个点形成的多边形的最优剖分。
那么状态转移方程为
d p [ i ] [ j ] = m i n ( d p [ i ] [ j ] , d p [ i ] [ k ] + d p [ k ] [ j ] + C o s t [ i ] [ k ] + C o s t [ j ] [ k ] ) dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]+Cost[i][k]+Cost[j][k]) dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]+Cost[i][k]+Cost[j][k])
因为要切出一个三角形,需要切两刀,注意,这里不要把i到j的边也算上。
因为再后续枚举更大的i到j的区间进行剖分时,小区间得到的底部会被当成大区间的三角形边来计算。如下图
当枚举到dp[i1][j1]时,不需要计算cost[i1][j1]。
否则在计算dp[i1][j2],以k2为顶点时,边i1到j1会被重复计算。
这篇关于ZOJ 3537的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!