Sicily 4697. Common Subsequence

软件学院2011级C语言机考热身题,就是软件学院2010级C语言机考题(我做到第3题才意识到这就是我当年考试的题目,当时10题AC了7题,排名是20左右?这个热身题系列拿了当年的前8题,这道题就是我当时做不出的第8题)。
现在回想起来,那10道题哪里是给刚学C语言的人考的?如果是大学前没接触过C语言之类编程语言的人,不掌握一定的技巧和知识根本AC不了5道题(就是那时候起,我才发现我编程还算不错……)貌似当年是2道题及格,记不太清楚了。
言归正传,这道题好像属于动态规划的范畴(意见保留,因为我现在还不知道动态规划是什么东西。如果是的话,那当年就是叫新生去做一道动态规划的题……)。相关方程是:
sub[ i ][ j ] = max( 0 or 1 + sub[ i + 1 ][ k + 1 ], sub[ i + 1 ][ j ] )
意思是,从字符串X的i位置和字符串Y的j位置开始,最大的公共子序列长度是:
1.若Y的j位置及以后无法与X的i位置匹配,这里取值为0;否则,将匹配位置记为k,这里取值为sub[ i + 1 ][ k + 1 ];
2.这里取值为sub[ i + 1 ][ j ];
以上两者较大的就是从字符串X的i位置和字符串Y的j位置开始的最大的公共子序列长度。直观上的感觉可以理解为:若在字符串Y中无法找到与当前字符串X的位置元素相匹配的,显然不存在公共子序列,所以所求为0。若能够找到相匹配的,就要考虑要不要匹配(因为若匹配了,匹配位置前面的字符串就不能再匹配了,有可能得不偿失),若选择匹配,那么X和Y的位置都向下移动一位,继续进行匹配;若选择不匹配,就将X的位置移向下一位,继续进行匹配。由于我们需要的是最长公共子序列,所以两种选择都要执行,然后取较大者。 我们所求明显是sub[ 0 ][ 0 ],这个过程依据上面的方式进行即可,可以用递归的形式实现,也可以用状态转移方程求出,前者递归层次为n,后者时间复杂度为O(n3),两个半斤八两,时间相差不大,就看个人喜好了。

Run Time: 0.02sec

Run Memory: 304KB

Code length: 842Bytes

Submit Time: 2012-01-07 14:19:34

// Problem#: 4697
// Submission#: 1179222
// The source code is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
// URI: http://creativecommons.org/licenses/by-nc-sa/3.0/
// All Copyright reserved by Informatic Lab of Sun Yat-sen University
#include <cstdio>
#include <cstring>
using namespace std;

int main()
{
    int N;
    int i, j, k;
    int Xlen, Ylen;
    int t1, t2;
    int sub[ 15 ][ 15 ];
    char X[ 14 ], Y[ 14 ];

    scanf( "%d", &N );
    while ( N-- ) {
        scanf( "%s%s", X, Y );
        Xlen = strlen( X );
        Ylen = strlen( Y );

        memset( sub, 0, sizeof( sub ) );
        for ( i = Xlen - 1; i >= 0; i-- ) {
            for ( j = Ylen - 1; j >= 0; j-- ) {
                for ( k = j; k < Ylen; k++ ) {
                    if ( X[ i ] == Y[ k ] )
                        break;
                }
                t1 = ( k == Ylen ? 0: 1 + sub[ i + 1 ][ k + 1 ] );
                t2 = sub[ i + 1 ][ j ];
                sub[ i ][ j ] = ( t1 > t2 ? t1: t2 );
            }
        }
        printf( "%d\n", sub[ 0 ][ 0 ] );
    }

    return 0;

}                                 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值