uva 10739【基础(区间)dp】

Uva 10739

题意:给定字符串,可以增加、删除、修改任意字符,问最少经过多少次操作使字符串回文。

题解:定义dp[l][r]表示把从l到r的子串Sl...Sr变成回文串需要操作的最少次数。字符可以增删改,有的博客说增删是一样的,有的说增比删开销大,我倾向于后者,但前者是对的。因为显然s[l]==s[r]时,dp[l][r]=dp[l+1][r-1];当两者不相等时,可以删去s[l]或者s[r],状态转移到dp[l+1][r]+1或dp[l][r-1]+1,但是增加怎么加?一样的,在状态dp[l][r-1]的左边添加's[l-1]'=s[r],或在状态dp[l+1][r]的右边添加's[r+1]'=s[l],画图看看,这和删除确实一样;自然,也可以把s[l],s[r]修改成相同的,状态转移到dp[l+1][r-1]+1。

 

直接循环里dp:

  

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 int dp[1050][1050];
 8 char s[1050];
 9 
10 int Min(int a,int b,int c)
11 {
12     int t=min(a,b);
13     return min(t,c);
14 }
15 
16 int main()
17 {
18     int T;
19     cin>>T;
20     for(int cas=1;cas<=T;cas++)
21     {
22         cin>>s;
23         int len=strlen(s);
24         for(int i=0;i<len;i++) dp[i][i]=0;
25         for(int i=len-1;i>=0;i--){
26             for(int j=i+1;j<len;j++){
27                 if(s[i]==s[j]) dp[i][j]=dp[i+1][j-1];
28                 else dp[i][j]=Min(dp[i+1][j],dp[i][j-1],dp[i+1][j-1])+1;
29             }
30         }
31         cout<<"Case "<<cas<<": "<<dp[0][len-1]<<endl;
32     }
33     return 0;
34 }

或者记忆化搜索(dfs):

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 int dp[1050][1050];
 8 char s[1050];
 9 
10 int dfs(int l,int r)
11 {
12     if(dp[l][r]!=-1) return dp[l][r];
13     if(l>=r) return dp[l][r]=0;
14     if(s[l]==s[r])
15         dp[l][r]=dfs(l+1,r-1);
16     else
17         dp[l][r]=min(dfs(l+1,r-1),min(dfs(l+1,r),dfs(l,r-1)))+1;
18     return dp[l][r];
19 }
20 
21 int main()
22 {
23     int T;
24     cin>>T;
25     for(int cas=1;cas<=T;cas++)
26     {
27         cin>>s;
28         int len=strlen(s);
29         memset(dp,-1,sizeof(dp));
30         cout<<"Case "<<cas<<": "<<dfs(0,len-1)<<endl;
31     }
32     return 0;
33 }

 

posted @ 2018-02-25 14:27  ╰追憶似水年華ぃ╮  阅读(223)  评论(0编辑  收藏  举报