杭电ACM1159

又是一道非常经典的动态规划问题:最长公共子序列。
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1159
题目大意:给出两个字符串,求出最长公共子序列的长度。
解题思路:本题求给出的两个字符串的最大公共子序列。首先要区分公共子字符串和公共子序列,公共子字符串要求选出的字符串必须在原字符串中是相邻的,而子序列只要满足原字符串的先后顺序即可。
本题可以认为两个字符串是两个字符数组,并且可以将一个竖起来,这样两个字符串就构成了一个矩阵,然后用一个二维数组记录信息。该二维数组的下标分别是两个字符串的对应下标,若当前字符相等,则该位置的数字是前一个位置的数字加一,若不等,则比较第一维下标加一的数字和第二维下标加一的数字,将较大的数字赋给该位置,该二维数组构建完成之后,找出数组中最大的数字即为所求数字。
好了,上代码:

#include <iostream>
#include <string.h>
using namespace std;
int main()
{
    int n,m;
    int max;
    int c[1001][1001];
    char a[1001];
    char b[1001];
    while(cin>>a>>b)
    {
        max=0;
        n = strlen(a);
        m = strlen(b);
        memset(c,0,sizeof(c));
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                if(a[i-1]==b[j-1])c[i][j]=c[i-1][j-1]+1;
                else{
                    if(c[i-1][j]>c[i][j-1])c[i][j] = c[i-1][j];
                    else c[i][j] = c[i][j-1];
                }
                if(max<c[i][j])max = c[i][j];
// cout<<c[i][j]<<endl;
            }
        }
        cout<<max<<endl;
    }
    return 0;
}

之前一直有一个地方不明白:if(a[i-1]==b[j-1])c[i][j]=c[i-1][j-1]+1; 就是这一行代码,按照算法的分析只要判断a[i]==b[j] 就可以了,为什么一定要判断前一个呢?而且写成a[i]==b[j]就会WA,而写成a[i-1]==b[j-1] 就可以AC,今天看了很多大神的博客终于明白了,万分感谢!
字符数组a[]和b[]在输入的时候一定是从a[0]和b[0]开始输入的,若两重for循环从0开始的话,则会出现c[0][0]=c[-1][-1]+1; 这毋庸置疑是错的,但是如果循环从1开始呢?一样有问题。因为这样一来当循环到a[lengtha]==b[lengthb]的时候,其实已经不是输入的内容了,而是越界的内容,因此判断一定会认为相等,从而得出错误的结果。
所以,if(a[i-1]==b[j-1])c[i][j]=c[i-1][j-1]+1; 这样写只是相当于将当前字符比较的状态保存到下一个单元而已,不会造成任何影响。

你可能感兴趣的:(动态规划,ACM,杭电)