poj 部分 DP 题

题目:http://poj.org/problem?id=3280

题意:给出一个字符串,可以增加 或 删除 个别字符,增加和删除都是有权重的,求在最小权重下把给的字符串变成回文串

感觉类似于求最长公共子序列的,把每个字符串增加和删除的权重存入两个数组,当前后对称的两个字符串相等时 dp[j][k] = dp[j + 1][k - 1],否则    dp[j][k] = min(   min(dp[j+1][k]+add[str[j]-'a'], dp[j][k-1]+add[str[k]-'a']),    min(dp[j+1][k]+sub[str[j]-'a'], dp[j][k-1]+sub[str[k]-'a']));

View Code
 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <vector>
 6 #define N 2010
 7 #define mod 100000000
 8 #define _clr(a,val) (memset(a,val,sizeof(a)))
 9 
10 using namespace std;
11 
12 typedef long long ll;
13 
14 char str[N];
15 int dp[N][N];
16 int add[N],sub[N];
17 int main()
18 {
19     int i;
20     int n,m;
21     char ch;
22     //freopen("data.txt","r",stdin);
23     while(scanf("%d%d",&n,&m) != EOF)
24     {
25         cin>>str;
26         for(i = 0; i < n; i++)
27         {
28             cin>>ch;
29             cin>>add[ch - 'a']>>sub[ch - 'a'];
30         }
31         for(int i = 1; i < m; i++)
32         {
33             for(int j = 0; j + i < m; j++)
34             {
35                 int k = j + i;
36                 if(str[j] == str[k]) dp[j][k] = dp[j + 1][k - 1];
37                 else
38                 {
39                     dp[j][k] = min(
40                     min(dp[j+1][k]+add[str[j]-'a'], dp[j][k-1]+add[str[k]-'a']),
41                     min(dp[j+1][k]+sub[str[j]-'a'], dp[j][k-1]+sub[str[k]-'a']));
42                 }
43             }
44         }
45         printf("%d\n",dp[0][m - 1]);
46     }
47     return 0;
48 }

题目:http://poj.org/problem?id=1191

黑书P116页有这道题目例题:上面解释:均方差 化简: sum(x1^2 + x2^2 + x3^2 ~~~~xn^2) / n  -  (x(平均) ^ 2)

考虑左上角坐标为(x1,y1)右下角坐标为 (x2,y2)的棋盘,设它的总和是s[X1,Y1,X2,Y2]切割k次以后得到的k+1块矩形的总分平方和最小值为d[K,X1,Y1,X2,Y2],则它可以沿着横线切,也可以沿着竖线切,然后选一块继续切,分析到这里,状态转移方程就可以写出来了;

d[k,x1,y1,x2,y2]=min

{

min{d[k-1,x1,y1,a,y2]+s[a+1,y1,x2,y2],d[k-1,a+1,y1,x2,y2]+s[x1,y1,a,y2]}(x1<=a<x2)  横切

min{d[k-1,x1,y1,x2,b]+s[x1,b+1,x2,y2],d[k-1,x1,b+1,x2,y2]+s[x1,y1,x2,b]}(y1<=b<y2)  竖切

}

代码里面sum数组存的值和解释中的s数组存的有点不同

View Code
 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <vector>
 6 #include <math.h>
 7 #define N 10
 8 #define inf 100000000
 9 #define _clr(a,val) (memset(a,val,sizeof(a)))
10 
11 using namespace std;
12 
13 typedef long long ll;
14 
15 int num[N][N][N][N][N + 7];
16 int sum[N][N][N][N];
17 int map[N][N];
18 int main()
19 {
20     int n,i,j,k;
21     int x1,x2,y1,y2;
22     int x,y;
23     int temp,kemp;
24     double tem;
25     //freopen("data.txt","r",stdin);
26     while(scanf("%d",&n) != EOF)
27     {
28         tem = 0;
29         for(i = 1; i <= 8; i++)
30         {
31             for(j = 1; j <= 8; j++)
32             {
33                 scanf("%d",&map[i][j]);
34                 tem += map[i][j];
35             }
36         }
37         int tsum;
38         tem /= n;
39         for(x1 = 1; x1 <= 8; x1++)
40         for(y1 = 1; y1 <= 8; y1++)
41         for(x2 = x1; x2 <= 8; x2++)
42         for(y2 = y1; y2 <= 8; y2++)
43         {
44             tsum = 0;
45             for(i = x1; i <= x2; i ++)
46             {
47                 for(j = y1; j <= y2; j++)
48                 tsum += map[i][j];
49             }
50             sum[x1][y1][x2][y2] = tsum;
51             num[x1][y1][x2][y2][1] = tsum * tsum;
52         }
53         for(k = 2; k <= n; k++)
54         {
55             for(x1 = 1; x1 <= 8; x1 ++)
56             for(y1 = 1; y1 <= 8; y1 ++)
57             for(x2 = x1; x2 <= 8; x2 ++)
58             for(y2 = y1; y2 <= 8; y2 ++)
59             {
60                 temp = inf;
61                 for(x = x1; x < x2; x ++)
62                 {
63                     kemp = min(num[x1][y1][x][y2][k - 1] + sum[x + 1][y1][x2][y2] * sum[x + 1][y1][x2][y2],
64                                num[x + 1][y1][x2][y2][k - 1] + sum[x1][y1][x][y2] * sum[x1][y1][x][y2]);
65                     if(temp > kemp) temp = kemp;
66                 }
67                 for(y = y1; y < y2; y++)
68                 {
69                     kemp = min(num[x1][y1][x2][y][k - 1] + sum[x1][y + 1][x2][y2] * sum[x1][y + 1][x2][y2],
70                                num[x1][y + 1][x2][y2][k - 1] + sum[x1][y1][x2][y] * sum[x1][y1][x2][y]);
71                     if(temp > kemp) temp = kemp;
72                 }
73                 num[x1][y1][x2][y2][k] = temp;
74             }
75         }
76         printf("%.3lf\n",sqrt( double (num[1][1][8][8][n]) / double (n) - tem * tem));
77     }
78     return 0;
79 }

题目:http://poj.org/problem?id=2948

题意:给出 n * m 的图,每个格子两种宝贝,一种是只能运到最左,一种是只能运到最上,如何运可以使得 最后运送的 宝贝最多(宝贝 1 + 宝贝 2)

先预处理nmap[r][c] (wmap[r][c]),表示如果传送带从(r,c)开始向上(左)传送,这条传送带一共能采到的宝贝的数量。   dpn[r][c]表示如果这点是向上的传送,那么矩形[(1,1)  (r,c)]所能采到的最多宝贝的数量,状态转移方程为: dpn[r][c] = nmap[r][c] + max(dpw[r][c-1], dpw[r][c-1]); 如果是向左传,则状态转移方程 dpw[r][c] = wmap[r][c] + max(dpw[r - 1][c], dpw[r - 1][c])

View Code
 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <vector>
 6 #include <math.h>
 7 #define N 510
 8 #define inf 100000000
 9 #define _clr(a,val) (memset(a,val,sizeof(a)))
10 
11 using namespace std;
12 
13 typedef long long ll;
14 
15 int nmap[N][N],wmap[N][N];
16 int dpn[N][N],dpw[N][N];
17 int main()
18 {
19     int i,j;
20     int n,m;
21     //freopen("data.txt","r",stdin);
22     while(scanf("%d%d",&n,&m) != EOF)
23     {
24         if(!n && !m) break;
25         _clr(wmap,0);
26         _clr(nmap,0);
27         _clr(dpn,0);
28         _clr(dpw,0);
29         for(i = 1; i <= n; i++)
30         {
31             for(j = 1; j <= m; j++)
32             {
33                 scanf("%d",&wmap[i][j]);
34                 wmap[i][j] += wmap[i][j - 1];
35             }
36         }
37         for(i = 1; i <= n; i++)
38         {
39             for(j = 1; j <= m; j++)
40             {
41                 scanf("%d",&nmap[i][j]);
42                 nmap[i][j] += nmap[i - 1][j];
43             }
44         }
45         for(i = 1; i <= n; i++)
46         {
47             for(j = 1; j <= m; j++)
48             {
49                 dpn[i][j] = nmap[i][j] + max(dpn[i][j - 1],dpw[i][j - 1]);
50                 dpw[i][j] = wmap[i][j] + max(dpn[i - 1][j],dpw[i - 1][j]);
51             }
52         }
53         int maxx = max(dpn[n][m],dpw[n][m]);
54         printf("%d\n",maxx);
55     }
56     return 0;
57 }

题目:http://poj.org/problem?id=2029

题意:题目描述好长,其实就是给你个n * m的图,然后上面有些点有柿子树(柿子树坐标给出),然后给你一个规定大小的矩形(位置不固定),问在这个矩形里最多可以有多少个柿子树

这个不是用dp做的。先求出从 1 到 j (j <= m)柿子树累加和,然后求出 行累加和 保存在num[i][j]里面,然后如果求 点(i,j)的柿子树的个数根据公式:tem = num[i][j] - num[i - c][j] - num[i][j - r] + num[i - c][j - r]; 其中 c r 是规定的矩形大小

View Code
 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <vector>
 6 #include <math.h>
 7 #define N 510
 8 #define inf 100000000
 9 #define _clr(a,val) (memset(a,val,sizeof(a)))
10 
11 using namespace std;
12 
13 typedef long long ll;
14 
15 int num[N][N];
16 int main()
17 {
18     int n,m;
19     int c,r;
20     int i,j;
21     int sum;
22     //freopen("data.txt","r",stdin);
23     while(scanf("%d",&sum), sum)
24     {
25         _clr(num,0);
26         scanf("%d%d",&m,&n);
27         int x,y;
28         while(sum --)
29         {
30             scanf("%d%d",&y,&x);
31             num[x][y] = 1;
32         }
33         scanf("%d%d",&r,&c);
34         for(i = 1; i <= n; i++)  
35         for(j = 1; j <= m; j++)
36         num[i][j] += num[i][j - 1];
37         for(i = 1; i <= n; i++)
38         for(j = 1; j <= m; j++)
39         num[i][j] += num[i - 1][j];
40         int ans = -1;
41         for(i = c; i <= n; i++)
42         {
43             for(j = r; j <= m; j++)
44             {
45                 int tem = num[i][j] - num[i - c][j] - num[i][j - r] + num[i - c][j - r];
46                 if(tem > ans || ans == -1) ans = tem;
47             }
48         }
49         printf("%d\n",ans);
50     }
51     return 0;
52 }

 

 

 

原文地址:https://www.cnblogs.com/fxh19911107/p/2635343.html