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就行了。(大白书p271)

  求最小费用需要用到分治的一些思想,当然主要还是dp。

  如下图的凸多边形(图来自这里),如果点1和点n还差1个点就成为三角形了,我们可以枚举这个点k,切两刀,取出K0(不能再切),变成K1和K2两块,以刚切的1->k和k->n这两条边为基边,继续分治切下去,直到剩下1个三角形为止。那么以edge[i][j]为基边来切开这个子凸多边形的费用是dp[i][j]=max(dp[i][j], dp[i][k]+dp[i][k]+cost[i][k]+cost[k][j]),所有点对的cost可以先求出来。注意在计算dp[i][j]时,dp[i][k]和dp[k][j]必须先求出来。

 1 //#include <bits/stdc++.h>
 2 #include <iostream>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <cmath>
 6 #include <map>
 7 #include <deque>
 8 #include <algorithm>
 9 #include <vector>
10 #include <iostream>
11 #define pii pair<int,int>
12 #define max(x,y) ((x)>(y)?(x):(y))
13 #define min(x,y) ((x)<(y)?(x):(y))
14 #define abs(x) ((x)<0?-(x):(x))
15 #define INF 0x3f3f3f3f
16 #define LL  long long
17 using namespace std;
18 const double PI  = acos(-1.0);
19 const int N=500;
20
21 struct node
22 {
23     int x,y;
24     node(){};
25     node(int x,int y):x(x),y(y){};
26 }Po[N], path[N];
27 int n, p, c[N][N], dp[N][N];
28
29
30 inline int cmp(node a,node b)
31 {
32     if(a.x==b.x)    return a.y<b.y;
33     return a.x<b.x;
34 }
35 inline int cross(node A,node p1,node p2)    //叉积,A是新来的点。若A在p1->p2左边,则结果为正。
36 {
37     return (p1.x-A.x)*(p2.y-A.y) - (p2.x-A.x)*(p1.y-A.y);
38 }
39 int get_cost(node a,node b){return abs(a.x+b.x)*abs(a.y+b.y)%p;}    //在a和b之间切开的费用
40
41 int ConvexHull(node *u,int n,node *path)    //求凸包,返回凸包中的点数
42 {
43     sort(u,u+n,cmp);            //先按x再按y排序
44     int top=0;
45     for(int i=0; i<n; i++)      //下凸包:从左到右
46     {
47         while(top>1 && cross(u[i],path[top-1],path[top-2])<=0 )  top--; //小于0,在右边
48         path[top++]=u[i];
49     }
50     int k=top;
51     for(int i=n-2; i>=0; i--)   //上凸包:从右到左
52     {
53         while(top>k && cross(u[i],path[top-1],path[top-2])<=0 )  top--;
54         path[top++]=u[i];
55     }
56     if(n>1) top--;  //起点是重复了的,要去掉
57     return top;
58 }
59
60
61
62 int cal()
63 {
64     if(n==3)    return 0;           //3点则0费用
65     memset(c,0,sizeof(c));
66     for(int i=0; i<n; i++)          //任意两点间连一条边的费用c
67         for(int j=i+2; j<n; j++)
68             c[i][j]=c[j][i]=get_cost( path[i], path[j] );
69     for(int i=0; i<n; i++)
70     {
71         for (int j=0; j<n; j++) dp[i][j]=INF;
72         dp[i][i+1] = 0;         //相邻两个点不能连线,可视为费用为0.
73     }
74     for(int j=2; j<n; j++)          //升序
75     {
76         for(int i=j-2; i>=0; i--)   //降序
77         {
78             for(int k=i+1; k<j; k++)    //枚举三角形顶点
79                 dp[i][j]=min(dp[i][j], dp[i][k]+dp[k][j]+c[i][k]+c[k][j]);
80         }
81     }
82     return dp[0][n-1];
83 }
84
85 int main()
86 {
87     //freopen("input.txt", "r", stdin);
88     while(~scanf("%d%d",&n,&p))
89     {
90         for(int i=0; i<n; i++)    scanf("%d%d",&Po[i].x,&Po[i].y);
91         if(ConvexHull(Po,n,path)<n)  puts("I can‘t cut.");
92         else                         printf("%d\n", cal());
93     }
94
95     return 0;
96 }

AC代码

时间: 2024-10-03 23:15:48

ZOJ 3537 Cake (区间DP,三角形剖分)的相关文章

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

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)

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3537 题目大意:给出一些点表示多边形顶点的位置,如果不是凸多边形(凸包)则不能切,直接输出"I can't cut."切多边形时每次只能在顶点和顶点间切,每切一次的花费为 cost(i, j) = |xi + xj| * |yi + yj| % p.问把多边形切成最多个不相交三角形的最小代价是多少. 解题思路:先求出凸包,接着可以用区间DP解决,设dp

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+最优三角剖分)

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 3905 Cake(贪心+dp)

动态规划题:dp[i][j]表示有i个Cake,给了Alice j个,先按照b排序,这样的话,能保证每次都能成功给Alice Cake,因为b从大到小排序,所以Alice选了j个之后,Bob最少选了j个,所以i>=2*j, 并且每次Alice选的时候Bob已经选过了.所以当i>=2 * j的时候Alice一定能选. 所以dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - 1] + ary[i].a); dp[i - 1][j]表示Alice不选第i个,dp[i