HDU 2476 String painter 动态规划-区间dp

来源:互联网 发布:安装caffe用linux 编辑:程序博客网 时间:2024/06/06 02:39

HDU 2476 String painter

题意:

给定一个字符串,和一个目标串,然后有一支画笔,每次可以将某一个区间内全部字符刷成你想要的字符,但是是一样的字符,比如 zzzzzfzzzzz,我可以用画笔把某一连续段刷成任意字符,我可以刷成zzaaafzzzzz,我刷了三个a。

问:最少刷几次,可以把给定字符串刷成目标串?

例如zzzzzfzzzzz,长度为11,下标看做0~10

先将0~10用画笔刷一次,变成aaaaaaaaaaa

1~9刷一次,abbbbbbbbba

2~8:      abcccccccba

3~7:       abcdddddcba

4~6:        abcdeeedcab

5:           abcdefedcab

这样就6次,变成了s2串了

每次刷一个区间


思路:

动态规划区间dp,第一次碰这种题很难理解。主要过程就是把大问题化成一个个       的小问题,从小问题逐渐把大问题递推出来

我们先从区间长度为1开始,统计每个长度为1的区间需要刷的次数,然后就能利用这些数据,去递推出长度为2的各个区间的次数。以此类推。

具体实现看代码:

#include<stdio.h>#include<string.h>int min(int a,int b){ return a<b?a:b; }int dp[110][110];//dp[i][j]就代表区间[i,j],包含i,j int dp1[110];char s[110],c[110];//给定字符串,目标串 int main(){while(~scanf("%s%s",s,c)){int len=strlen(s);memset(dp,0,sizeof(dp));for(int l=1;l<=len;l++) //区间长度,从小到大递推 for(int i=0;i<len-l+1;i++) //假设一个左端点,则右端点j=i+l-1,且<len; {int j=i+l-1;//右端点    //现在记大区间为dp[i][j](未知),小区间dp[i+1][j](已求出) dp[i][j]=dp[i+1][j]+1;//刷完小区间,加一次把i这个字符刷掉for(int k=i+1;k<=j;k++) //扫描小区间{if(c[i]==c[k])//小区间内某字符等于大区间左端点{ //再把小区间分开,i这个字符就可以跟随dp[i+1][k]一起刷掉 //再加上dp[k+1][j]即可//与原数值比较大小 dp[i][j]=min(dp[i][j],dp[i+1][k]+dp[k+1][j]);}} }//到了这里还没有结束!!/*因为上面的dp是按左端点处理的,当区间长度大于1时,左端点就永远到不了字符串的末尾 末尾的dp也就没有全面进行 *///下面单独对右端点进行动态规划 for(int i=0;i<len;i++)dp1[i]=dp[0][i];//用dp1[i]表示区间[0][i]的最优解for(int i=0;i<len;i++){if(s[i]==c[i])//该字符无需更改 {//那么只需要改该字符左边的字符 if(i==0)//特殊情况 dp1[i]=0;else dp1[i]=dp1[i-1];//因为第i个字符不需要做什么 }elsefor(int k=0;k<i;k++) //一定要从0开始, dp1[i]=min(dp1[i],dp1[k]+dp[k+1][i]);} printf("%d\n",dp1[len-1]);}return 0;}


模板:

        memset(dp,0,sizeof(dp)); //二维         int i,j,l,k;          for(l = 2; l <= n; ++l) //假设区间长度,递推         {              for(i = 1; i <= n - l + 1; ++i)  //左端点             {                  j = i + l - 1; //右端点                 dp[i][j] = 2100000000; //初值(有时初值跟之前的状态有关系,不一定常数)                 for(k = i; k < j; ++k)  //找中转站                 {                      dp[i][j]=min(dp[i][j],dp[i][k] + dp[k + 1][j] +权值);                  }              }          }          printf("%d\n", dp[1][n]); 


有时候,可能区间左端点访问不到末尾,从而得不到最优解,需要再动态规划一次,比如上面的例题。








0 0
原创粉丝点击