题目: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']));
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数组存的有点不同
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])
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 是规定的矩形大小
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 }