题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3537
题目大意:给出一些点表示多边形顶点的位置,如果不是凸多边形(凸包)则不能切,直接输出"I can‘t cut."
切多边形时每次只能在顶点和顶点间切,每切一次的花费为 cost(i, j) = |xi + xj| * |yi + yj| % p。
问把多边形切成最多个不相交三角形的最小代价是多少。
解题思路:先求出凸包,接着可以用区间DP解决,设dp[i][j]为以i为起点,j为终点的凸包被切成三角形的最小花费。
那么可以得到状态转移方程:dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]+cost[i][k]+cost[k][j])。
不懂的可以看下图(非原创):
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<vector> 5 #include<cmath> 6 #include<algorithm> 7 using namespace std; 8 const int INF=0x3f3f3f3f; 9 const int N=505; 10 const double eps = 1e-9; 11 12 int n,mod; 13 int dp[N][N],cost[N][N]; 14 15 struct P 16 { 17 double x, y; 18 P(double x=0, double y=0):x(x), y(y) {} 19 double add(double a, double b){ 20 if(fabs(a+b)<eps*(fabs(a)+fabs(b))) return 0; 21 return a+b; 22 } 23 P operator + (P p){ 24 return P(add(x, p.x), add(y, p.y)); 25 } 26 P operator - (P p){ 27 return P(add(x, -p.x), add(y, -p.y)); 28 } 29 P operator *(double d){ 30 return P(x*d, y*d); 31 } 32 double dot(P p){ //点积 33 return add(x*p.x, y*p.y); 34 } 35 double det(P p){ //差积 36 return add(x*p.y, -y*p.x); 37 } 38 }ps[N]; 39 40 double dist(P a, P b){ 41 return sqrt((b-a).dot(b-a)); 42 } 43 44 bool cmp_x(const P& p, const P& q){ 45 if(p.x!=q.x) return p.x < q.x; 46 return p.y < q.y; 47 } 48 49 vector<P> convex_hull(P *ps, int n){ 50 sort(ps,ps+n,cmp_x); 51 int k = 0; //凸包顶点数 52 vector<P> qs(n*2); 53 //构造凸包的下侧 54 for(int i=0; i<n; i++) 55 { 56 while(k>1 && (qs[k-1]-qs[k-2]).det(ps[i]-qs[k-1])<=0) k--; 57 qs[k++] = ps[i]; 58 } 59 //构造凸包的上侧 60 for(int i=n-2,t=k; i>=0; i--) 61 { 62 while(k>t && (qs[k-1]-qs[k-2]).det(ps[i]-qs[k-1])<=0) k--; 63 qs[k++] = ps[i]; 64 } 65 qs.resize(k-1); 66 return qs; 67 } 68 69 int getcost(P p1,P p2){ 70 return abs((int)p1.x+(int)p2.x)*abs((int)p1.y+(int)p2.y)%mod; 71 } 72 73 int main(){ 74 while(~scanf("%d%d",&n,&mod)){ 75 for(int i=0;i<n;i++){ 76 scanf("%lf%lf",&ps[i].x,&ps[i].y); 77 } 78 vector<P>tp; 79 tp=convex_hull(ps,n); 80 if(tp.size()<n){ 81 puts("I can‘t cut."); 82 continue; 83 } 84 //注意,用获得的凸包做DP,即使用tp做DP,保证凸包上的点的顺序 85 memset(cost,0,sizeof(cost)); 86 memset(dp,0,sizeof(dp)); 87 for(int i=0;i<n;i++){ 88 for(int j=i+2;j<n;j++){ 89 cost[i][j]=getcost(tp[i],tp[j]); 90 } 91 } 92 for(int len=3;len<n;len++){ 93 for(int i=0;i+len<n;i++){ 94 int j=i+len; 95 dp[i][j]=INF; 96 for(int k=i+1;k<=j-1;k++){ 97 dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]+cost[i][k]+cost[k][j]); 98 } 99 } 100 } 101 printf("%d\n",dp[0][n-1]); 102 } 103 return 0; 104 }
原文地址:https://www.cnblogs.com/fu3638/p/8809003.html
时间: 2024-11-04 15:27:18