ZOJ 3537 Cake(凸包+区间DP)

题目链接: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

ZOJ 3537 Cake(凸包+区间DP)的相关文章

ZOJ - 3537 Cake (凸包+区间DP+最优三角剖分)

Description 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 endpoin

ZOJ 3537 Cake (区间DP,三角形剖分)

题意: 给出平面直角坐标系上的n个点的坐标,表示一个多边形蛋糕,先判断是否是凸多边形,若否,输出"I can't cut.".若是,则对这个蛋糕进行3角形剖分,切n-3次变成n-2份三角形蛋糕给小伙伴吃,但是每切一次需要一个费用,公式是:cost[i][j] = |xi + xj| * |yi + yj| % p 表示在两点i和j之间切一刀的费用.问最少费用是多少? 思路: 判断是否凸多边形需要用到求凸包的Andrew算法,时间复杂度为O(nlogn),然后判断凸包内的点数是否为n就行

zoj 3537 Cake (凸包判定+区间dp)

Cake Time Limit: 1 Second      Memory Limit: 32768 KB 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 eac

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] + c

zoj 3537 Cake (凸包确定+间隔dp)

Cake Time Limit: 1 Second      Memory Limit: 32768 KB 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 eac

ZOJ - 3537 —— Cake

题目:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=23543 1. 因为没有三个点在同一直线上,即每个点都是多边形的一个顶点而不会有点在某条边上,所以要判断这个多边形是不是凸多边性,可以用像凸包问题那样做,得到的凸包的关节点以及它们的个数num,若num==n (全体点的个数),那么是凸多边形:否则,不是凸多边形. 2. 如果判断是凸多边形后,就要开始正式的DP了. 我们都知道,这种成环的数组的DP,可以将环拆开,变成区

ZOJ 3537 Cake

区间DP. 首先求凸包判断是否为凸多边形. 如果是凸多边形:假设现在要切割连续的一段点,最外面两个一定是要切一刀的,内部怎么切达到最优解就是求子区间最优解,因此可以区间DP. #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<iostream> using namespace std; const int MAXN = 1000; con

zoj 3537 Cake(区间dp)

这道题目是经典的凸包的最优三角剖分,不过这个题目给的可能不是凸包,所以要提前判定一下是否为凸包,如果是凸包的话才能继续剖分,dp[i][j]表示已经排好序的凸包上的点i->j上被分割成一个个小三角形的最小费用,那么dp[i][j] = min(dp[i][k]+dp[k][j]+cost[i][k]+cost[k][j]),其中,(j >= i+ 3,i+1<=k<=j-1,cost[i][k]为连一条i到k的线的费用). 上一个图,来自博客http://blog.csdn.net

Cake(凸包+区间DP)

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 v