UVA 10739 String to Palindrome(動態規劃 迴文)

賈樹丙發表於2013-07-26

String to Palindrome

題目大意:給出一個字串s,現在可以進行3種操作(新增字母,刪除字母,替換字母),將其變成迴文串,求出最少的操作次數。比如abccda,可以用刪除操作,刪除b,d兩步可變成迴文;但如果用替換操作,把b換成d則只需要1步。

分析:剛開始我一直考慮它是否具有最優子結構性質,直到現在,還是不明白為什麼可以用動態規劃來做,大神若是看見,還望指教。

  由於新增字母和刪除字母的效果是一樣的,因此我們這裡就只進行刪除和替換操作。令dp[i][j]表示從第 i 到第 j 個字母變成迴文所需要最少的運算元。

  轉移方程為:當是s[i]==s[j]時,dp[i][j] = dp[i+1][j-1];此外dp[i][j] = min(dp[i+1][j],dp[i+1][j-1],dp[i][j-1]) + 1;  dp[i+1][j-1]+1 是替換操作,其他兩種是刪除操作。

  初始條件是:j<=i 時dp[i][j] = 0; 如果只是單一的字母,它本身就是迴文

遞推程式碼如下:

 1 # include<cstdio>
 2 # include<cstring>
 3 # include<iostream>
 4 using namespace std;
 5 char s[1005];
 6 int dp[1005][1005];
 7 int main()
 8 {
 9     int T,cas;
10     scanf("%d",&T);
11     for(cas=1; cas<=T; cas++)
12     {
13         scanf("%s",s);
14         int len =strlen(s);
15         int i,j;
16         for(i=0; i<len; i++)
17                 dp[i][i] = 0;
18         for(i=len-1; i>=0; i--)
19             for(j=i+1; j<len; j++)
20             {
21                 if(s[i]==s[j])
22                     dp[i][j] = dp[i+1][j-1];
23                 else
24                     dp[i][j] = min(min(dp[i+1][j],dp[i+1][j-1]),dp[i][j-1])+1;
25             }
26         printf("Case %d: %d\n",cas,dp[0][len-1]);
27     }
28     return 0;
29 }

遞迴程式碼如下:

 1 # include<cstdio>
 2 # include<cstring>
 3 # include<iostream>
 4 using namespace std;
 5 char s[1005];
 6 int dp[1005][1005];
 7 int DP(int x,int y){
 8     if(dp[x][y] != -1)
 9         return dp[x][y];
10     if(y <= x )
11         return dp[x][y] = 0;
12     if(s[x] == s[y])
13         dp[x][y] = DP(x+1,y-1);
14     else
15         dp[x][y] = min( min(DP(x+1,y),DP(x+1,y-1)),(DP(x,y-1))) + 1;
16         return dp[x][y];
17 }
18 int main(){
19     int T,cas;
20     scanf("%d",&T);
21     for(cas=1;cas<=T;cas++){
22         scanf("%s",s);
23         int len =strlen(s);
24         memset(dp,-1,sizeof(dp));
25         printf("Case %d: %d\n",cas,DP(0,len-1));
26     }
27     return 0;
28 }

 

相關文章