問題描述:ios
給一個有n個頂點的凸多邊形,有不少方法進行三角剖分(polygon triangulation) 。給每一個三角形規定一個權函數w(i,j,k)(好比三角形的周長或者三頂點的權和或者三角形的面積等等),求讓全部三角形權和最大的方案。函數
分析:spa
這個問題的關鍵在於狀態的定義,由於若是容許隨意切割,顯然任意「半成品」 多邊形的各個頂點能夠是原多邊形中隨意選取的,很難簡潔的定義成狀態。但咱們又能夠發現,對於同一種切割方法,咱們能夠有多種切割順序,但切割方法就已經決定了這個方法產生的結果,咱們只要計算其中一種切割順序就行了,因此不如把決策順序規範化。.net
定義 d[i,j] 爲從頂點 i 開始到頂點 j 所構成的多邊形的最大三角剖分權和,則邊 i→j 在此多邊形內必定剛好屬於一個三角形 i→j→k ,因此多邊形就被分紅了三部分:▲ikj 及其左右兩部分子多邊形。這個切割方法保證了兩個子多邊形它們的頂點編號是連續的。因此咱們只須要每次將表明這個多邊形的兩個頂點(始、末)做爲分割後的其中一個三角形的一條邊,而後枚舉第三個頂點 k 的狀況,再依次分割下去直到分割完成。code
因此,有狀態轉移方程:d[i,j] = max{d[i,k]+d[k,j]+w(i,j,k)},時間複雜度爲O(n3)blog
結合一道具體的題目來加深一下理解ci
題目連接:get
https://cn.vjudge.net/problem/UVA-1331博客
題意:string
給定一個n邊形,要你求將這個n邊形分割成若干三角形後,其中面積最大的三角形的最小值
分析:
典型的最優三角剖分問題,狀態轉移方程:d[i][j] = min{max{SΔijk,d[i][k],d[k][j]}} (i<k<j)
不過這裏須要注意的是,這道題並無指明這個多邊形的凹凸性,因此對於凹多邊形的狀況,須要加上一個判斷,即判斷Δijk是不是合法的三角形,若是Δijk內部含有多邊形的一個頂點,那麼就是不合法的
具體分析細節,這篇博客寫的不錯https://blog.csdn.net/c20190102/article/details/75418824
代碼:
1 #include<iostream> 2 #include<stdio.h> 3 #include<cstring> 4 #include<cmath> 5 using namespace std; 6 const int maxn = 60; 7 const int INF = 0x3f3f3f3f; 8 int x[maxn], y[maxn]; 9 double dp[maxn][maxn]; 10 int n; 11 double area(int a, int b, int c) 12 { 13 double ans; 14 ans = (x[a] * y[b] + x[b] * y[c] + x[c] * y[a] - x[a] * y[c] - x[b] * y[a] - x[c] * y[b]) * 1.0 / 2; 15 return abs(ans); 16 } 17 18 int judge(int i, int j, int k) 19 { 20 for(int v = 0; v < n; v++) 21 { 22 if(v == i || v == j || v == k) 23 continue; 24 else 25 { 26 double sum = area(i, j, v) + area(i, k, v) + area(j, k, v); 27 if(abs(sum - area(i, j, k)) <= 0.001) //由於有浮點數偏差,這裏初略認爲小於0.001即爲相等 28 return 0; 29 } 30 } 31 return 1; 32 } 33 int main() 34 { 35 int t; 36 cin >> t; 37 while(t--) 38 { 39 memset(dp, 0, sizeof(dp)); 40 cin >> n; 41 for(int i = 0; i < n; i++) 42 { 43 cin >> x[i] >> y[i]; 44 } 45 //i<k<j 注意邊界 46 for(int i = n - 3; i >= 0; i--) 47 { 48 for(int j = i + 2; j <= n - 1; j++) 49 { 50 dp[i][j] = INF; 51 for(int k = i + 1; k < j; k++) 52 { 53 if(judge(i, j, k)) 54 dp[i][j] = min(dp[i][j], max(area(i, j, k), max(dp[i][k], dp[k][j]))); 55 } 56 } 57 } 58 printf("%.1lf\n", dp[0][n - 1]); 59 } 60 return 0; 61 }