1. 程式人生 > >【動態規劃】NYOJ最長公共子序列

【動態規劃】NYOJ最長公共子序列

最長公共子序列

時間限制:3000 ms  |  記憶體限制:65535 KB 難度:3
描述
咱們就不拐彎抹角了,如題,需要你做的就是寫一個程式,得出最長公共子序列。
tip:最長公共子序列也稱作最長公共子串(不要求連續),英文縮寫為LCS(Longest Common Subsequence)。其定義是,一個序列 S ,如果分別是兩個或多個已知序列的子序列,且是所有符合此條件序列中最長的,則 S 稱為已知序列的最長公共子序列。
輸入
第一行給出一個整數N(0<N<100)表示待測資料組數
接下來每組資料兩行,分別為待測的兩組字串。每個字串長度不大於1000.
輸出
每組測試資料輸出一個整數,表示最長公共子序列長度。每組結果佔一行。
樣例輸入
2
asdf
adfsd
123abc
abc123abc
樣例輸出
3
6

思路如下:

題目一開始不會,因為DP都沒怎麼學過,做這道題就是為了學習的,還是看了別人的一些解釋才算是寫出來程式碼了。

其實思路很簡單:

首先,定義個dp[i][j]表示字串S1的第i個字元(包括i)以前的所有字元  字串S2的第j個字元以前的(包括j)所有字元 之間最大的公共子序列的長度。

其次,可以列出來DP公式:dp[i][j]=dp[i-1][j]+dp[i][j-1]

然後,設定兩個for迴圈對字串S1和字串S2遍歷,並設定一個標記sum=0。當s1[i-1]==s2[j-1](即s1的第i個字元和s2的第j個字元相同),則讓dp[i][j]=dp[i][j]+1。如果不相等的話,此時需要找s1的第i個字元內和s2的第j個字元內的最長串:sum=dp[i][j]。

最後,迴圈結束,輸出sum。

#include <iostream>
#include <string.h>
using namespace std;

char s1[1005],s2[1005];
int dp[1005][1005]; 

int max(int a,int b)
{
	return a>b?a:b;
}
int main()
{
	int t;
	int len1,len2;
	int i,j;
	cin>>t;
	while(t--)
	{
		cin>>s1>>s2;
		len1=strlen(s1);
		len2=strlen(s2);
		memset(dp,0,1005*1005);

		int sum=0;
		for(i=1;i<=len1;i++)  //雙層for迴圈遍歷兩個陣列
		{
			for(j=1;j<=len2;j++)
			{
				if(s1[i-1]==s2[j-1]) //如果相等,則令最大串長度加1
				{
					dp[i][j]=dp[i-1][j-1]+1;
				}
				else   //如果不相等,求出此時的s1的i個字元內和s2的j個字元內的最大串長度
					dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
				if(sum<dp[i][j])  
					sum=dp[i][j];
			}
		}
		cout<<sum<<endl;
	}
	return 0;
}