1. 程式人生 > >NYOJ 36 最長公共子序列

NYOJ 36 最長公共子序列

最長公共子序列

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

/*求最長公共子序列。動態規劃問題。

  設序列X = (x1; x2; . . . ; xm) 和Y =(y1; y2; . . . ; yn) 的最長公共子序列為
  Z = (z1; z2; . . . ; zk),

. 若xm = yn,則zk = xm = yn,且Zk-1 是Xm-1 和Yn-1 的最長公共子序列。
. 若xm != yn 且zk != xm,則Z 是Xm-1 和Y 的最長公共子序列。
. 若xm != yn 且zk != yn,則Z 是X 和Yn-1 的最長公共子序列。

  其中Xm-1 = (x1; x2; . . . ; xm-1), Yn-1 = (y1; y2; . . . ; yn-1), Zk-1 = (z1; z2; . . . ; zk-1)
*/

一般解法,不優化空間。

 
#include <stdio.h>
#include <string.h>

#define MAX 1010
int dp[MAX][MAX] = {0};

void lcs(const char *x, int m, const char *y, int n)
{
	int i,j;
	for (i=0; i<=m; i++)
	{
		dp[i][0] = 0;
	}
	for (j=0;j<=n; j++)
	{
		dp[0][j] = 0;
	}
	for (i=1; i<=m; i++)
	{
		for (j=1; j<=n; j++)
		{
			if (x[i-1] == y[j-1])
			{
				dp[i][j] = dp[i-1][j-1] + 1;
			}
			else
			{
				dp[i][j] = dp[i-1][j] > dp[i][j-1]?dp[i-1][j] : dp[i][j-1];
			}
		}
	}
}

int main()
{
	int m;
	char x[MAX],y[MAX];
	scanf("%d",&m);
	while (m--)
	{
		int xlen,ylen;
		scanf("%s%s",x,y);
		xlen = strlen(x);
		ylen = strlen(y);
		lcs(x,xlen,y,ylen);
		printf("%d\n",dp[xlen][ylen]);
	}
	return 0;
}        

滾動陣列,優化空間

 
#include <stdio.h>
#include <string.h>

#define MAX 1001
short dp[2][MAX];

int main()
{
	int m;
	char x[MAX],y[MAX];
	scanf("%d",&m);
	while (m--)
	{
		int xlen,ylen;
		int i,j,e = 0;
		scanf("%s%s",x,y);
		xlen = strlen(x);
		ylen = strlen(y);
		memset(dp,0,sizeof(dp));
		for (i=1; i<=xlen;i++)
		{
			e = 1-e;
			for (j=1; j<=ylen; j++)
			{
				if (x[i-1] == y[j-1])
				{
					dp[e][j] = dp[1-e][j-1] + 1;
				}
				else
				{
					dp[e][j] = dp[e][j-1] > dp[1-e][j]?dp[e][j-1] : dp[1-e][j];
				}
			}
		}
		printf("%d\n",dp[e][ylen]);
	}
	return 0;
}