Common Subsequence
(最长公共子序列)
Time Limit: 2 Seconds Memory Limit: 65536 KB
Description
A subsequence of a given sequence is the given sequence with some elements (possible none) left out. Given a sequence X = another sequence Z = is a subsequence of X if there exists a strictly increasing sequence of indices of X such that for all j = 1,2,...,k, xij = zj. For example, Z = is a subsequence of X = with index sequence . Given two sequences X and Y the problem is to find the length of the maximum-length common subsequence of X and Y.
The program input is from a text file. Each data set in the file contains two strings representing the given sequences. The sequences are separated by any number of white spaces. The input data are correct. For each set of data the program prints on the standard output the length of the maximum-length common subsequence from the beginning of a separate line.
Sample Input
abcfbc abfcab
programming contest
abcd mnp
Sample Output
4
2
0
Source
本题是动态规划的经典题目,求两个字符串的最长公共子序列,关于求单个字符串的最长有序子序列(较为简单),请看文章:[ACM_POJ_2533]Longest Ordered Subsequence。
思路分析:
设c[i][j]为字符串a的第i个字符与字符串b的第j个字符为止的最长公共子序列长度,那么有两种情况:
- 当a[i] == b[j]时,c[i][j]应该是前一个状态的最长公共子序列长度 + 1,而前一个状态是c[i - 1][j]呢,还是c[i][j - 1]?两者都不是,因为a[i]可能与b[j - 1]匹配,那么a[i]就不可能再同b[j]比配了,否则相当于某个字母与另一个字符串中的字母重复匹配多次,这必然是非法的,因此上一个状态应是c[i - 1][j - 1],即c[i][j] = c[i - 1][j - 1] + 1;
- 当a[i] != b[j]时,上一个状态可能是c[i - 1][j]或c[i][j - 1],而既然要找最长公共子序列,自然是找最大的一个,即c[i][j] = max(c[i - 1][j], c[i][j - 1])。
可得代码如下:
ZOJ:
#include<iostream>
#include<string>
using namespace std;
int c[1001][1001];
int getc(int i, int j){
if(i >= 0 && j >= 0)
return c[i][j];
else
return 0;
}
int main(){
string a, b;
while(cin >> a >> b){
int max = 0;
for(int i = 0; i < a.length(); ++i){
for(int j = 0; j < b.length(); ++j){
if(a[i] == b[j]){
c[i][j] = getc(i - 1, j - 1) + 1;
}else{
c[i][j] = getc(i - 1, j) > getc(i, j - 1) ? getc(i - 1, j) : getc(i, j - 1);
}
if(c[i][j] > max)
max = c[i][j];
}
}
cout << max << endl;
}
return 0;
}
NYOJ:
#include<iostream>
#include<string>
using namespace std;
int c[1001][1001];
int getc(int i, int j){
if(i >= 0 && j >= 0)
return c[i][j];
else
return 0;
}
int main(){
int n;
string s1, s2;
cin >> n;
while(n--){
int max = 0;
cin >> s1 >> s2;
for(int i = 0; i < s1.length(); ++i){
for(int j = 0; j < s2.length(); ++j){
if(s1[i] == s2[j]){
c[i][j] = getc(i - 1, j - 1) + 1;
}else{
c[i][j] = getc(i - 1, j) > getc(i, j - 1) ? getc(i - 1, j) : getc(i, j - 1);
}
if(c[i][j] > max)
max = c[i][j];
}
}
cout << max << endl;
}
return 0;
}
关于为什么我在这道题里似乎多此一举地多给出一个南阳理工学院在线评测系统的来源,是因为它的设计比较不错,有些人可能会说一个ACM在线评测系统并不需要什么好看的界面,重要的是内涵,但作为一个对前端比较发烧的人来说,它不仅仅只是进行评测,也注重了用户体验,如提交可以直接在问题页面完成,当做比较难的题目时,不需要在题目及提交页面反复切换;代码高亮等等。而且在题目中绞尽脑汁之余,可以看到一个赏心悦目的界面,不也是一件令人放松的事么?而且它也并不缺少内涵,不像其它OJ系统一般,只能看到自己的代码(有的还看不到),通过做题积累NYOJ币,还可以看到别人的最佳解决方案,利于ACMer的学习,更加人性化。
=======================签 名 档=======================
原文地址(我的博客):http://www.clanfei.com/2012/04/484.html
欢迎访问交流,至于我为什么要多弄一个博客,因为我热爱前端,热爱网页,我更希望有一个更加自由、真正属于我自己的小站,或许并不是那么有名气,但至少能够让我为了它而加倍努力。。
=======================签 名 档=======================