ZOJ3537:Cake

——将一块多边形的蛋糕切成许多三角形的小蛋糕,每切一刀有一个花费,求最小的花费。

——dp,多边形的三角剖分

——url:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3537

————————————————————————————————————————————————————————————————

【转载】

在一个n个顶点的凸多边形中,插入对角线(对角线两两不相交)将多边形划分为三角形。
总共需要n-3条弦,将多边形切成n-2个小三角形。

设凸多边形n个顶点顺序为p[1],p[2],……,p[n],
它有n条边:<p[1]p[2]>,<p[2]p[3]>,……,<p[n-1]p[n]>,<p[n]p[1]>。
按顶点编号顺序,将其中的n-1条边写成下面这个序列:
<p[1]p[2]><p[2]p[3]><p[3]p[4]>……<p[n-1]p[n]>,
则多边形的三角划分和这个序列的全括号化存在着一一对应的关系。
以五边形为例:


选定多边形的一条边<p[1]p[n]>为基边,无论怎样分区域,基边总能在分成的三角形区域中的一个中。
该三角形区域又将凸多边形区域分成三个部分

——————————————————————————————————————————————————

设F[I][J](I<J)表示从顶点I到顶点J的凸多边形三角剖分后所得到的最大乘积,我们可以得到下面的动态转移方程:
F[I][J]=Min{F[I][K]+F[K][J]+M[I][K]+M[K][J]}

M[I][J]表示沿着I,J两点切的花费。(若I==J+1或者I==J-1表示这条边是原多边形的边,则M[I][J]=0)

——————————————————————————————————————————————————

先对所有点按极角排序,然后扫一遍数组计算叉积,判断是否是凸多边形。

代码见下,需要注意是循环变量的循环次序

I必须从大到小枚举,这样可以保证在计算DP[I][J]时,DP[I][K]和DP[K][J]已经在前面算出。

另外一个枚举方法:

for (j=2;j<n;j++)

    for (i=j-2;>i=0;i--)

         for (k=i+1;k<=j-1;k++)

View Code
 1 #include<stdio.h>
2 #include<math.h>
3 #include<stdlib.h>
4 #include<algorithm>
5 using namespace std;
6 #define N 400
7 #define eps 1e-8
8 #define oo 0x7ffffff
9 double dp[N][N], m[N][N];
10 int i, j, k, n, P, u, v;
11 bool flag;
12 struct cpoint
13 {
14 double x, y;
15 } p[N], bp;
16 double sqr(double x)
17 {
18 return x * x;
19 }
20 int dcmp(double x)
21 {
22 if (x < -eps
23 )
24 return -1;
25 else
26 return x > eps;
27 }
28 double cross(cpoint p0, cpoint p1, cpoint p2)
29 {
30 return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);
31 }
32 double dissqr(cpoint p1, cpoint p2)
33 {
34 return sqr(p1.x - p2.x) + sqr(p1.y - p2.y);
35 }
36 int polarcmp(const cpoint &p1, const cpoint &p2)
37 {
38 int u = dcmp(cross(bp, p1, p2));
39 return u > 0 || (u == 0 && dcmp(dissqr(bp, p1) - dissqr(bp, p2)) < 0);
40 }
41
42 int main()
43 {
44 while (scanf("%d%d", &n, &P) != EOF)
45 {
46 for (i = 0, k = 0; i < n; i++)
47 {
48 scanf("%lf%lf", &p[i].x, &p[i].y);
49 u = dcmp(p[i].x - p[k].x);
50 v = dcmp(p[i].y - p[k].y);
51 if (v < 0 || (v == 0 && u < 0))
52 k = i;
53 }
54 bp = p[k];
55 sort(p, p + n, polarcmp);
56 flag = true;
57 for (i = 0; i < n - 2; i++)
58 if (dcmp(cross(p[i], p[i + 1], p[i + 2])) < 0)
59 {
60 flag = false;
61 break;
62 }
63 if (flag)
64 {
65 for (i = 0; i < n; i++)
66 for (j = 0; j < n; j++)
67 if (i == j + 1 || i + 1 == j)
68 m[i][j] = 0;
69 else
70 m[i][j] = abs((int) p[i].x + (int) p[j].x)
71 * abs((int) p[i].y + (int) p[j].y) % P;
72 for (i = 0; i < n; i++)
73 for (j = 0; j < n; j++)
74 dp[i][j] = oo;
75 for (i = 0; i < n - 1; i++)
76 dp[i][i + 1] = 0;
77 dp[n - 1][0] = 0;
78 for (i = n - 3; i >= 0; i--)
79 for (j = i + 2; j < n; j++)
80 for (k = i + 1; k <= j - 1; k++)
81 if (dp[i][j] > dp[i][k] + dp[k][j] + m[i][k] + m[k][j])
82 dp[i][j] = dp[i][k] + dp[k][j] + m[i][k] + m[k][j];
83 printf("%.f\n", dp[0][n - 1]);
84 }
85 else
86 printf("I can't cut.\n");
87 }
88 return 0;
89 }

  

posted on 2011-09-17 15:24  风也轻云也淡  阅读(367)  评论(0编辑  收藏  举报