软件学院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;
}