凸多边形最优三角剖分的问题”
有关“凸多边形最优三角剖分的问题”,这是《计算机算法设计与分析》(王晓东编著 第三版)第三章“动态规划”中的一道例题,代码如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
“Point.h”class Point{public: int x; int y;};"MWTri.cpp"#include<iostream>#include"math.h"#include"Point.h"using namespace std;#define MAX 100int t[MAX][MAX];int s[MAX][MAX];int w(Point pt1,Point pt2,Point pt3){ int d1=(int)sqrt((pt2.y-pt1.y)*(pt2.y-pt1.y)+(pt2.x-pt1.x)*(pt2.x-pt1.x)); int d2=(int)sqrt((pt3.y-pt1.y)*(pt3.y-pt1.y)+(pt3.x-pt1.x)*(pt3.x-pt1.x)); int d3=(int)sqrt((pt3.y-pt2.y)*(pt3.y-pt2.y)+(pt3.x-pt2.x)*(pt3.x-pt2.x)); return d1+d2+d3;}void MinWeightTriangulation(Point * point,int n,int t[][MAX],int s[][MAX]){ for(int i=1;i<=n;i++) t[i][i]=0; for(int r=2;r<=n;r++) for(int i=1;i<=n-r+1;i++){ int j=i+r-1; t[i][j]=t[i+1][j]+w(point[i-1],point[i],point[j]); s[i][j]=i; for(int k=i+1;k<j;k++){ int u=t[i][k]+t[k+1][j]+w(point[i-1],point[k],point[j]); if(u<t[i][j]){ t[i][j]=u; s[i][j]=k; } } }}void main(){ Point pt[5]; pt[0].x=4; pt[0].y=1; pt[1].x=3; pt[1].y=2; pt[2].x=2; pt[2].y=2; pt[3].x=1; pt[3].y=1; pt[4].x=1; pt[4].y=0; //pt[5].x=4; //pt[5].y=1; /*for(int m=1;m<=4;m++) for(int n=1;n<=4;n++) s[m][n]=0;*/ MinWeightTriangulation(pt,4,t,s); for(int m=1;m<=4;m++) for(int n=1;n<=4;n++) cout<<m<<" "<<n<<" "<<s[m][n]<<endl; } |
程序运行结果如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
1 1 01 2 11 3 11 4 12 1 02 2 02 3 22 4 23 1 03 2 03 3 03 4 34 1 04 2 04 3 04 4 0Press any key to continue |
#include "windows.h"#include <iostream>using namespace std;/* 问题描述: 把多边形0,...,n-1剖分成n-2个三角形,求给定的权值最小 本程序定义权为:剖分弦的长度和 程序功能: 用两种方法求解上述问题(针对任意权的和针对本问题的) 解法本质都是动态规划 PS : 动态规划很难,本程序难免会有错误,但是基本思路是正确的 注释得很详细了*/const V = 5;//5个顶点void LoadData(float dist[][V]);/* 解法1: 重新定义权为:剖分弦的长度和加上多边形的周长(显然等价),重新求解 本函数还适用于任何定义在剖分后的三角形上的权的情况(修改一下) 例如权为三角形的面积的面积平方和*/void minWeightTriangulation1(int n, float dist[][V], float t[][V], int s[][V]);void ShowSolution1(int s[][V], int i, int j);/* 解法2: 针对此问题的求解方法,不具有普遍适用性*/void minWeightTriangulation2(int n, float dist[][V], float t[][V+1], int s[][V+1]);void ShowSolution2(int s[][V+1], int i, int j);void end();int main(){ float dist[V][V]; float t1[V][V]; int s1[V][V]; float t2[V+1][V+1]; int s2[V+1][V+1]; LoadData(dist); minWeightTriangulation1(V, dist, t1, s1); cout<<"最优剖分权:"<<t1[1][4] - 2 - 1.414 * 3<<"\t剖分弦:\t";//要减去周长 ShowSolution1(s1, 1, 4); cout<<endl; minWeightTriangulation2(V, dist, t2, s2); cout<<"最优剖分权:"<<t2[0][5]<<"\t剖分弦:\t"; ShowSolution2(s2, 0, 5); cout<<endl; return 0;}void LoadData(float dist[][V]){ dist[0][1] = dist[1][0] = 1; dist[1][2] = dist[2][1] = 1; dist[2][3] = dist[3][2] = 1.414; dist[3][4] = dist[4][3] = 1.414; dist[4][0] = dist[0][4] = 1.414; dist[0][2] = dist[2][0] = 1.414; dist[0][3] = dist[3][0] = 2; dist[1][3] = dist[3][1] = 2.236; dist[1][4] = dist[4][1] = 2.828; dist[2][4] = dist[4][2] = 2;}float Weight(float dist[][V], int i, int j, int k){ return dist[i][j] + dist[j][k] + dist [k][i];}void minWeightTriangulation1(int n, float dist[][V], float t[][V], int s[][V]){/* t[i][j]表示顶点为i-1,i,...,j的多边形的最优三角剖分值 s[i][j]表示顶点为i-1,i,...,j的多边形的最优三角剖分方法,剖分点为s[i][j] 退化情况1:s[i][j]==i 剖分成 三角形i-1,i,j 和 多边形i,...,j 退化情况2:s[i][j]==j-1 剖分成 多边形i-1,...,j-1和 三角形i-1,j-1,j 一般情况:k = s[i][j] 剖分成 多边形i-1,...,k 和 多边形 k,...,j 权的定义:多边形的周长+剖分的弦长,所以对两种特殊情况进行了处理*/ for (int i = 1; i < n; i++) t[i][i] = 0;//只有两个顶点认为权是0 for (int r = 2; r < n; r++)//r+1边形 { for (i = 1; i <= n - r; i++) { int j = i + r -1; /*当i-1,i,j是相邻三个顶点时(r==2),权为 t[i+1][j] + Weight(dist, i-1, i, j) 否则,权为 t[i+1][j] + Weight(dist, i-1, i, j) - dist[i][j] 因为t[i+1][j]和eight(dist, i-1, i, j)分别计算了 一次dist[i][j] */ t[i][j] = t[i+1][j] + Weight(dist, i-1, i, j) - (r==2?0:dist[i][j]); s[i][j] = i; for (int k = i + 1; k < j; k++) {/* 当取剖分i-1,j-1时权为 t[i][k] + t[k+1][j] + dist[i-1][j] + dist[k][j] 因为t[k+1][j]退化,权为0,故把边dist[k][j]补上 否则权为t[i][k] + t[k+1][j] + dist[i-1][j] */ float u = t[i][k] + t[k+1][j] + dist[i-1][j] + (k+1==j?dist[k][j]:0); if (u<t[i][j]) { t[i][j] = u; s[i][j] = k; } } } }}void ShowSolution1(int s[][V], int i, int j){ if (i + 1 >= j) return; int k = s[i][j]; if (k == i) {//退化情况1:s[i][j]==i 剖分成 三角形i-1,i,j 和 多边形i,...,j cout<<'('<<i<<','<<j<<") "; ShowSolution1(s, i+1, j); } else if (k==j-1) {//退化情况2:s[i][j]==j-1 剖分成 多边形i-1,...,j-1和 三角形i-1,j-1,j ShowSolution1(s, i, j-1); cout<<'('<<i-1<<','<<j-1<<") "; } else {//一般情况:k = s[i][j] 剖分成 多边形i-1,...,k 和 多边形 k,...,j ShowSolution1(s, i, k); cout<<'('<<i-1<<','<<k<<") "; cout<<'('<<k<<','<<j<<") "; ShowSolution1(s, k+1, j); }}float Distance(float dist[][V], int i, int j){ if (i == (j + 1)%V || j == (i +1)%V) return 0; return dist[i][j];}void minWeightTriangulation2(int n, float dist[][V], float t[][V+1], int s[][V+1]){/* t[i][j]表示从顶点i开始的j个顶点围成的多边形(j边形)的最优剖分的权 s[i][j]表示从顶点i开始的j个顶点围成的多边形(j边形)的最优剖分的方法, 剖分点为 i + s[i][j] 退化情况1:s[i][j]==1 剖分成 三角形i,i+1,i+j-1 和 多边形 i+1,...,i+j-1 退化情况2:s[i][j]==j-2剖分成 多边形i,...,i+j-2 和 三角形 i,i+j-2,i+j-1 一般情况 :k = s[i][j] 剖分成 多边形i,...,i+k 和 多边形 i+k,...,i+j-1 */ const MAX = 10000; float temp, q; int kk; for (int k = 0; k < n; k++) { t[k][2] = 0; t[k][3] = 0; } for (int r = 4; r <= n; r++) for (int i = 0; i < n; i++) { for (q = MAX, kk = 1; kk <= r - 2; kk++) {/* 划分成子问题 多边形i,...,i+kk 和 多边形 i+kk,...,i+r-1 划分弦为 (i, ((i+kk)%n) 和 ((i+kk)%n, (i+r-1)%n) 由于Distance函数中相邻弦长度为0,故退化情况自动包含 */ temp = t[i][(kk+1)%n] + t[(i+kk)%n][(n+r-kk)%n] + Distance(dist, i, ((i+kk)%n) ) + Distance(dist, (i+kk)%n, (i+r-1)%n); if (temp < q) { k = kk; q = temp; } } t[i][r] = q; s[i][r] = k; if (r==n) break;//一旦r==n可以马上跳出本层循环 }}void ShowSolution2(int s[][V+1], int i, int j){ if (j<=3) return; int k = s[i][j]; if (k==1) {//退化情况1:s[i][j]==1 剖分成 三角形i,i+1,i+j-1 和 多边形 i+1,...,i+j-1 cout<<'('<<i+1<<','<<i+j-1<<") "; ShowSolution2(s, i+1, j-1); } else if (s[i][j]==j-1) {//退化情况2:s[i][j]==j-2剖分成 多边形i,...,i+j-2 和 三角形 i,i+j-2,i+j-1 cout<<'('<<i<<','<<i+j-1<<") "; ShowSolution2(s, i, j-1); } else {//一般情况 :k = s[i][j] 剖分成 多边形i,...,i+k 和 多边形 i+k,...,i+j-1 ShowSolution2(s, i, k+1); cout<<'('<<i<<','<<i+k<<") "; ShowSolution2(s, i+k, j-k); cout<<'('<<i+k<<','<<i+j-1<<") "; }}

浙公网安备 33010602011771号