1、三角形最有分割

   Zoj   3537  cake  

   题目大意:给定n个点的坐标,先问这些点是否能组成一个凸包,如果是凸包,问用不相交的线来切这个凸包使得凸包只由三角形组成,根据costi, j = |xi + xj| * |yi + yj| % p算切线的费    用,问最少的切割费用。

  

  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 }
View Code 

 2http://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; 

   

 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 } 
View Code

 

 3POJ 2955 Brackets(区间DP, 记忆化搜索)

    不知道这个代码为什么一直TLE 。。。

 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 }
View Code

 

 AC代码:

 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 }
View Code

还有好多经典区间dp,慢慢学习中。。。。