1、三角形最有分割
Zoj 3537 cake
题目大意:给定n个点的坐标,先问这些点是否能组成一个凸包,如果是凸包,问用不相交的线来切这个凸包使得凸包只由三角形组成,根据costi, j = |xi + xj| * |yi + yj| % p算切线的费 用,问最少的切割费用。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cmath> 2 #include<cstdio> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 7 using namespace std; 8 const int INF = 1e8; 9 const int maxn = 1010; 10 struct Point 11 { 12 int x,y; 13 }point[maxn]; 14 15 int cost[maxn][maxn]; 16 int n,m,dp[maxn][maxn]; 17 18 int abs(int x) 19 { 20 return x < 0 ? -x : x; 21 } 22 23 Point s[maxn] , t[maxn]; 24 25 int xmult(Point p1 , Point p2, Point p0) //叉积 26 { 27 return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y); 28 } 29 30 bool cmp(const Point &s1 , const Point &s2) 31 { 32 if(s1.y == s2.y) return s1.x < s2.x; 33 return s1.y < s2.y; 34 } 35 36 int Graham(Point *point , int n) //凸包 37 { 38 int i; 39 sort(point , point + n , cmp); 40 s[0] = point[0]; 41 s[1] = point[1]; 42 int cnt = 1; 43 for(i = 0;i < n;i ++) 44 { 45 while(cnt && xmult(s[cnt] , point[i] , s[cnt - 1]) >= 0) 46 cnt --; 47 s[++cnt] = point[i]; 48 } 49 50 int mid = cnt; 51 for(i = n - 2;i >= 0;i --) 52 { 53 while(cnt > mid &&xmult(s[cnt] , point[i] , s[cnt - 1]) >= 0) 54 cnt --; 55 s[++cnt] = point[i]; 56 } 57 return cnt; 58 } 59 60 int Count(Point a , Point b) //花费 61 { 62 return (abs(a.x + b.x) * abs(a.y + b.y)) % m; 63 } 64 int main() 65 { 66 while(scanf("%d%d",&n,&m) !=EOF) 67 { 68 int i , j , k; 69 for(i = 0;i < n;++ i) 70 scanf("%d%d", &point[i].x , &point[i].y); 71 72 int tot = Graham(point , n); 73 if(tot < n) 74 printf("I can't cut.\n"); 75 else 76 { 77 memset(cost , 0 , sizeof(cost)); 78 for(i = 0;i < n;i ++) 79 for(j = i + 2;j < n;j ++) 80 cost[i][j] = cost[j][i] = Count(s[i] , s[j]); 81 82 for(i = 0;i < n;i ++) 83 { 84 for(j = 0;j < n;j ++) 85 { 86 dp[i][j] = INF; 87 } 88 dp[i][(i + 1) % n] = 0; 89 } 90 for(i= n - 3;i >= 0;i --) 91 for(j = i + 2;j < n;j ++) 92 for(k = i + 1;k <= j - 1;k ++) 93 { 94 dp[i][j] = min(dp[i][j] , dp[i][k] + dp[k][j] + cost[i][k] + cost[k][j]); 95 } 96 printf("%d\n",dp[0][n-1]); 97 } 98 } 99 return 0; 100 }
2、http://lightoj.com/volume_showproblem.php?problem=1422
题意:有N个宴会,对于每一个宴会,女猪脚都要穿一种礼服,礼服可以套着穿,但是脱了的不能再用,参加宴会必须按顺序来,从第一个到第N个,问参加这些宴会最少需要几件礼服。
思路:定义dp[i][j] 代表从第i个到第j个最少的穿衣数量,由逆序推导可以判断前一天是否在后面出现过,及分为两种情况
(1)第i个需要再穿一件 :dp[i][j] = dp[i+1][j] + 1;
(2)第i个不需要再穿一件:dp[i][j] = min(dp[i][j] , dp[i+1][k-1] + dp[k][j]);
PS:对于边界值dp[i][i] = 1;
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 //区间dp 2015/9/17 2 #include<cmath> 3 #include<cstdio> 4 #include<cstring> 5 #include<iostream> 6 #include<algorithm> 7 8 using namespace std; 9 const int maxn = 110; 10 11 int a[maxn] , dp[maxn][maxn]; 12 int n; 13 14 int main() 15 { 16 int t , cas = 0; 17 scanf("%d" ,& t); 18 while(t --) 19 { 20 scanf("%d", & n); 21 memset(dp , 0 ,sizeof(dp)); 22 memset(a, 0 , sizeof(a)); 23 for(int i = 1;i <= n;i ++) //边界值 24 dp[i][i] = 1; 25 for(int i = 1;i <= n;i ++) 26 scanf("%d", &a[i]); 27 for(int i = n;i >= 1;i --) 28 { 29 for(int j = i + 1;j <= n;j ++) 30 { 31 dp[i][j] = dp[i+1][j] + 1; 32 for(int k = i + 1;k <= j;k ++) 33 { 34 if(a[i] == a[k]) 35 dp[i][j] = min(dp[i][j] , dp[i+1][k-1] + dp[k][j]); 36 } 37 } 38 } 39 printf("Case %d: %d\n", ++cas , dp[1][n]); 40 } 41 return 0; 42 }
3、POJ 2955 Brackets(区间DP, 记忆化搜索)
不知道这个代码为什么一直TLE 。。。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 // 区间dp + 记忆化搜索 2 #include<cmath> 3 #include<cstdio> 4 #include<string> 5 #include<cstring> 6 #include<iostream> 7 #include<algorithm> 8 9 using namespace std; 10 const int maxn = 110; 11 int dp[maxn][maxn]; 12 string str; 13 14 bool check(int i,int j) 15 { 16 return (str[i] == '(' && str[j] == ')') || 17 (str[i] == '[' && str[j] == ']') || 18 (str[i] == '{' && str[j] == '}'); 19 } 20 21 int dfs(int l , int r) 22 { 23 int cnt , ans = 0; 24 if(l >= r) return dp[l][r] = 0; // 边界判断 25 if(dp[l][r] != -1) dp[l][r]; // 记忆化搜索 26 cnt = dfs(l + 1 , r); 27 for(int i = l + 1;i <= r;i ++) 28 { 29 if(check(l , i)) // 匹配态 30 { 31 cnt = dfs(l + 1 , i - 1) + dfs(i + 1 , r) + 1; 32 if(cnt > ans) ans = cnt; 33 } 34 } 35 return dp[l][r] = ans; 36 } 37 int main() 38 { 39 while(cin>>str) 40 { 41 if(str[0] == 'e') 42 break; 43 memset(dp , -1 , sizeof(dp)); 44 dfs(0 , str.size() - 1); 45 printf("%d\n" ,2 * dp[0][str.size() - 1]); 46 } 47 return 0; 48 }
AC代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <cstdio> 2 #include <cstring> 3 4 #define check(i, j) ((str[i] == '[' && str[j] == ']') || (str[i] == '(' && str[j] == ')')) 5 #define max(a, b) ((a) > (b) ? (a) : (b)) 6 7 const int MAXN = 110; 8 char str[MAXN]; 9 int dp[MAXN][MAXN], n; 10 11 int solve(int i, int j) { 12 if (dp[i][j]) return dp[i][j]; 13 if (j <= i) return 0; 14 if (j == i + 1) { 15 if (check(i, j)) 16 return dp[i][j] = 2; 17 else 18 return 0; 19 } 20 21 dp[i][j] = solve(i + 1, j); 22 for (int k = i + 1; k <= j; k++) 23 if (check(i, k)) 24 dp[i][j] = max(dp[i][j], solve(i + 1, k - 1) + solve(k + 1, j) + 2); 25 return dp[i][j]; 26 } 27 28 int main() { 29 while (scanf("%s", str) && strcmp(str, "end")) { 30 memset(dp, 0, sizeof(dp)); 31 printf("%d\n", solve(0, strlen(str) - 1)); 32 } 33 return 0; 34 }
还有好多经典区间dp,慢慢学习中。。。。