Problem B
Time Limit : 2000/1000ms (Java/Other) Memory Limit : 65536/32768K (Java/Other)
Total Submission(s) : 8 Accepted Submission(s) : 5
abcfbc abfcab programming contest abcd mnp
4 2 0
题目大意:
求最长公共子序列长度。
最长公共子序列的定义是 如abcde和dbada的最长公共字串为bd 或者 ad。
思路:
假设给出一个图哈
a b c f b c
a 1 1 1 1 1 1
b 1 2 2 2 2 2
f 1 2 2 3 3 3
c 1 2 3 3 3 4
a 1 2 3 3 3 4
b 1 2 3 3 4 4
图的意思是用 竖着的去匹配横着的,坐标 (i , j) 代表的是走遍 1- j 这个字符串去匹配 1 - i 这个字符串。
lcs 基本问题,对吗?可以直接模板,但是要搞明白为什么要这么写。
这也是个动态规划的问题,对吧?那么,我们来给他定义状态。
状态: 当前字符串能匹配到的长度。
如果当前 s2 字符和 s1 字符相同,那么没的说,len ++
如果当前 s2 字符长度和 s1 不同,那么,他的长度和之前相同
因为是利用二维数组进行遍历,保证了每个字符都会去匹配,是这样吗?
比如 abfc 去匹配 abcfbc 匹配到的长度是 4
如何来的?
我们先用a去遍历 abcfbc 得到最长为 1
再用 ab 去扫描 得到为 2 这都不用解释吧?
当我们用 abf 去扫描的话 得到了3
最后 abfc 扫描, 这个 c 匹配的那个呢?
你看哈,反正 用abfc 匹配 abcfb 得到 3 对吧?那么既然 c 和最后一个 c 相同 len ++,没问题吧?
由此 dp[ i ] [ j ] = dp [ i - 1 ] [ j - 1 ] +1 ; 这个是 s1 [ i ] = = s2 [ j ]
因为 dp [ i - 1 ] [ j - 1 ] 代表用 1 - j - 1 这个字符串 例子中就是 abf 去 匹配 1 - i-1 abcfb 显然。
另一个 不相等的情况:
dp [ i ][ j ]=max(dp[ i-1 ][ j ],dp[ i ][ j-1 ]);
为什么呢?读者自己思考,答案在对后面!
感想:
lcs.......刚才被老鼠咬了...
AC代码:
<span style="color:#111111;">#include <stdio.h>
#include<iostream>
#include<cstdio>
#include<string.h>
#include<algorithm>
using namespace std;
int dp[1005][1005];
int main()
{
int n,i,j;
// freopen("r.txt","r",stdin);
string s1,s2;
char arr[1005];
while(~scanf("%s",arr))
{
s1=arr;
scanf("%s",arr);
s2=arr;
memset(dp,0,sizeof(dp));
for(i=0;i<s1.length();i++)
{
for(j=0;j<s2.length();j++)
{
if(s1[i]==s2[j])
{
dp[i+1][j+1]=dp[i][j]+1;
}
else
{
dp[i+1][j+1]=max(dp[i][j+1],dp[i+1][j]);
}
}
}
cout<<dp[s1.length()][s2.length()]<<endl;
}
}
</span>
答案:
你看哈 ,如果用 abc 去 匹配 ab 得到什么? 得到 2
那么 a b
a 1 1
b 1 2
c 1 2
c 这里的第二个 2 怎么来的??
不就是找的之前最大长度吗? 之前最大长度保存在哪? 你完全可以扫描一遍之前的dp数组,但那样的话,会增加时间复杂度 对吧?
和 i j 关系最亲密的是谁? dp [ i -1 ] [ j ] 和 dp [ i ] [ j - 1 ]
为什么?思考他的状态怎么定义的!! 匹配是相互的!就写这么多吧,要是还不理解,就多想几遍。
反正这是一个 lcs 模板...