1. 程式人生 > >迴文字串 (動態規劃,最長公共子序列)

迴文字串 (動態規劃,最長公共子序列)

迴文字串

時間限制:3000 ms | 記憶體限制:65535 KB 難度:4
描述
所謂迴文字串,就是一個字串,從左到右讀和從右到左讀是完全一樣的,比如"aba"。當然,我們給你的問題不會再簡單到判斷一個字串是不是迴文字串。現在要求你,給你一個字串,可在任意位置新增字元,最少再新增幾個字元,可以使這個字串成為迴文字串。
輸入
第一行給出整數N(0<N<100)
接下來的N行,每行一個字串,每個字串長度不超過1000.
輸出
每行輸出所需新增的最少字元數
樣例輸入
1
Ab3bd
樣例輸出
2
剛開始看到這道題,看了一會沒看出頭緒,然後看人家說是要用動態規劃裡面的最長公共子序列,可是還是想不出為什麼。後來同學同學問我這道題,就仔細的想了想。結果發現還真是。
思路:題目中是要求將字串補成迴文串時最少補充的字元。那麼我們可以這樣想,我們先有一個迴文串,然後故意去掉幾個。。。就成了題目中的測試案例。
      然後呢,假設去掉的那些字元我們保留為空格,我們想,既然之前是迴文的,當我們反轉過來背去掉剩下的,然後去掉空格,必然會有些字元還是匹配的,這部分匹配的就是不用動的部分,一個字串當作模式串,一個當作匹配串,從頭到尾匹配,總有一種情況下匹配的字元達到最大,這便是我們把他們變回迴文串時不用改動的最大數值,然後根據題意,只要我們拿字串的總長度減去這個數,便是需要改動的最少個數。也就轉化成了求最長公共子序列問題。
 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
 
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
char *reverse( char a[])
{
	char *b=new char[1005];
	int t=strlen(a);
	int i,j;
	for(i=t-1,j=0;i>=0;j++,i--){
		b[j]=a[i];
	}
	return b;
}
int dp[1000][1000];
int main()
{
	int n;
	cin>>n;
	while(n--)
	{
        char a[1005];
        cin>>a;
        int str = strlen(a);
        string b=reverse(a);
        //cout<<b<<endl;
        for(int i =0;i <= str;i ++){
        	for(int j =0 ;j <= str; j++){
        		if(i == 0||j == 0) dp[i][j]=0;
        		else if(b[i-1] == a[j-1]) dp[i][j]=dp[i-1][j-1]+1;
        		else dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
        	}
        }
        
        /*for(int i = 0; i <= str; i ++){
        	for(int j = 0;j <= str; j++){
        		cout<<dp[i][j]<<" ";
        	}
        	cout<<endl;
        }*/
        cout<<str-dp[str][str]<<endl;
	}
	return 0;
} 
對案例:asdfgg 進行的測試。

看下圖,理解最長公共子序列
案例是:ACDDEB和ADC