NOI 2.6 动态规划 1808:公共子序列

题目来源:http://noi.openjudge.cn/ch0206/1808/

1808:公共子序列

总时间限制: 1000ms    内存限制: 65536kB

描述

我们称序列Z = < z1, z2,..., zk >是序列X = < x1,x2, ..., xm >的子序列当且仅当存在 严格上升 的序列< i1,i2, ..., ik >,使得对j = 1, 2, ... ,k, xij = zj。比如Z = < a, b, f, c> X = < a, b, c, f, b, c >的子序列。

现在给出两个序列XY,你的任务是找到XY的最大公共子序列,也就是说要找到一个最长的序列Z,使得Z既是X的子序列也是Y的子序列。

输入

输入包括多组测试数据。每组数据包括一行,给出两个长度不超过200的字符串,表示两个序列。两个字符串之间由若干个空格隔开。

输出

对每组输入数据,输出一行,给出两个序列的最大公共子序列的长度。

样例输入

abcfbc        abfcab
programming    contest
abcd           mnp

样例输出

4
2
0

-----------------------------------------------------

解题思路

二维动态规划: dp[i][j]表示s1[i:s1.end())s2[j:s2.end())的公共子串

实现时用两个一维数组dp1dp分别代表dp[i][j]dp[i+1][j]以节省内存

-----------------------------------------------------

代码

//1808:公共子序列
//总时间限制: 1000ms 内存限制: 65536kB
//描述
//我们称序列Z = < z1, z2, ..., zk >是序列X = < x1, x2, ..., xm >的子序列当且仅当存在 严格上升 的序列< i1, i2, ..., ik >,使得对j = 1, 2, ... ,k, 有xij = zj。比如Z = < a, b, f, c > 是X = < a, b, c, f, b, c >的子序列。
//
//现在给出两个序列X和Y,你的任务是找到X和Y的最大公共子序列,也就是说要找到一个最长的序列Z,使得Z既是X的子序列也是Y的子序列。
//输入
//输入包括多组测试数据。每组数据包括一行,给出两个长度不超过200的字符串,表示两个序列。两个字符串之间由若干个空格隔开。
//输出
//对每组输入数据,输出一行,给出两个序列的最大公共子序列的长度。
//样例输入
//abcfbc         abfcab
//programming    contest 
//abcd           mnp
//样例输出
//4
//2
//0

// 动态规划: dp[i][j]表示s1[i:s1.end())与s2[j:s2.end())的公共子串

#include<fstream>
#include<iostream>
#include<string>
using namespace std;

int main()
{
#ifndef ONLINE_JUDGE
	ifstream fin("0206_1808.txt");
	string s1,s2;
	int n1,n2,i,j;
	while(fin >> s1 >> s2)
	{
		/*int dp[201][201] = {};
		n1 = s1.size();
		n2 = s2.size();
		if (n1==0 || n2==0)
		{
			cout << 0 << endl;
			continue;
		}
		dp[n1-1][n2] = 0;
		for (i=n1-1; i>=0; i--)
		{
			for (j=n2-1; j>=0; j--)
			{
				if (s1.at(i)==s2.at(j))
				{
					dp[i][j] = max(dp[i][j+1]+1,dp[i+1][j]);
				}
				else
				{
					dp[i][j] = max(dp[i][j+1],dp[i+1][j]);
				}
			}
		}
		cout << dp[0][0] << endl;*/

		int dp[201] = {};				// 模拟dp[i+1][j]
		int dp1[201] = {};				// 模拟dp[i][j]
		n1 = s1.size();
		n2 = s2.size();
		if (n1==0 || n2==0)
		{
			cout << 0 << endl;
			continue;
		}
		dp[n2] = 0;
		for (i=n1-1; i>=0; i--)
		{
			for (j=n2-1; j>=0; j--)
			{
				if (s1.at(i)==s2.at(j))
				{
					dp1[j] = dp[j+1]+1;
				}
				else
				{
					dp1[j] = max(dp1[j+1],dp[j]);
				}
			}
			for (j=n2-1; j>=0; j--)
			{
				dp[j] = dp1[j];
			}
		}
		cout << dp1[0] << endl;
	}
	fin.close();
	return 0;
#endif
#ifdef ONLINE_JUDGE
	string s1,s2;
	int n1,n2,i,j;
	while(cin >> s1 >> s2)
	{
		/*int dp[201][201] = {};
		n1 = s1.size();
		n2 = s2.size();
		if (n1==0 || n2==0)
		{
			cout << 0 << endl;
			continue;
		}
		dp[n1-1][n2] = 0;
		for (i=n1-1; i>=0; i--)
		{
			for (j=n2-1; j>=0; j--)
			{
				if (s1.at(i)==s2.at(j))
				{
					dp[i][j] = max(dp[i][j+1]+1,dp[i+1][j]);
				}
				else
				{
					dp[i][j] = max(dp[i][j+1],dp[i+1][j]);
				}
			}
		}
		cout << dp[0][0] << endl;*/

		int dp[300] = {};				// 模拟dp[i+1][j]
		int dp1[300] = {};				// 模拟dp[i][j]
		n1 = s1.size();
		n2 = s2.size();
		if (n1==0 || n2==0)
		{
			cout << 0 << endl;
			continue;
		}
		dp[n2] = 0;
		for (i=n1-1; i>=0; i--)
		{
			for (j=n2-1; j>=0; j--)
			{
				if (s1.at(i)==s2.at(j))
				{
					dp1[j] = dp[j+1]+1;
				}
				else
				{
					dp1[j] = max(dp1[j+1],dp[j]);
				}
			}
			for (j=n2-1; j>=0; j--)
			{
				dp[j] = dp1[j];
			}
		}
		cout << dp1[0] << endl;
	}
#endif
}


猜你喜欢

转载自blog.csdn.net/da_kao_la/article/details/80509219