• 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 }

     

     

     

  • 相关阅读:
    搭建 Linux 下 GitLab 服务器(转)
    sql语法:inner join on, left join on, right join on具体用法
    Android Studio之同一应用创建多个Activity(一)
    java环境变量配置
    老鸟的Python新手教程
    域名注冊以及域名解析设置
    Android在WebView上构建Web应用程序
    利用JasperReport+iReport进行Web报表开发
    android App Widgets
    多数据库下activiti的流程定义缓存问题
  • 原文地址:https://www.cnblogs.com/fxh19911107/p/2635343.html
Copyright © 2020-2023  润新知