ZOJ 3537 Cake 求凸包 区间DP
题意:给出一些点表示多边形顶点的位置(如果多边形是凹多边形就不能切),切多边形时每次只能在顶点和顶点间切,每切一次都有相应的代价。现在已经给出计算代价的公式,问把多边形切成最多个不相交三角形的最小代价是多少。
思路:首先判断多边形是否是凸多边形,之后就是区间dp了。
求出凸包后,按逆时针来看。
设置dp[i][j]为从顶点i到顶点j所围成凸多边形的最优解。
枚举切点k (i < k < j)
dp[i][j] = min(dp[i][k] + dp[k][j] + cost[i][k] + cost[k][j]);
#include<bits/stdc++.h> using namespace std; const int MAXN = 310; struct point { int x,y; friend bool operator < (const point &a,const point &b) { if (a.y == b.y) return a.x < b.x; return a.y < b.y; } }src[MAXN]; int cost[MAXN][MAXN]; int N,P; int dp[MAXN][MAXN]; point save[MAXN],tmp[MAXN]; int cross(point p0,point p1,point p2) { return (p1.x - p0.x) * (p2.y - p0.y) - (p1.y - p0.y) * (p2.x - p0.x); } int graphm(point * p,int n) { sort(p,p + n); save[0] = p[0]; save[1] = p[1]; int top = 1; for(int i = 0 ; i < n ; i++){ while(top && cross(save[top],p[i],save[top-1]) >= 0)top--; save[++top] = p[i]; } int mid = top; for(int i = n - 2 ; i >= 0 ; i--){ while(top > mid && cross(save[top],p[i],save[top-1]) >= 0) top--; save[++top]=p[i]; } return top; } int getcost(point a,point b) { return (abs(a.x + b.x) * abs(a.y+b.y)) % P; } int main() { while (scanf("%d%d",&N,&P) != EOF) { for (int i = 0 ; i < N ; i++) scanf("%d%d",&src[i].x,&src[i].y); int num = graphm(src,N); if (num < N) { printf("I can't cut.\n"); } else { memset(cost,0,sizeof(cost)); for (int i = 0 ; i < N ; i++) { for (int j = i + 2 ; j < N ; j++) cost[i][j] = cost[j][i] = getcost(save[i],save[j]); } memset(dp,0x3f,sizeof(dp)); for (int i = 0 ; i < N ; i++) dp[i][(i + 1) % N] = 0; for (int d = 2 ; d <= N ; d++) { for (int i = 0 ; i + d - 1 < N ; i++) { int j = d + i - 1; 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]); } } printf("%d\n",dp[0][N - 1]); } } return 0; }
今年输的,明年全都要赢回来