uva 10723 Cyborg Genes
题意:给出两个串a,b,去构建另一个串,新构建出来的串要满足两个性质。一,在这个新的串中选出一个子集是a串,另外选出一个子串是b,满足这个条件后,要求这个串的长度最短。也可以这样说,ab两个串合并为一个新串,不改变a,b串本身的相对位置,但是要求新串长度最短。输出这样的新串的个数
所以基本上可以想到,是和LCS有关的,再细想,那就是算出LCS的长度,然后ab两串长度之和减去LCS的长度,相当于ab两串合并为一串,消去他们的共有元素,那么新串中还是包含了a,b串的所有元素还是可以选出一部分子集来得到a或b串的。
但问题时,怎么构建,另外有多少种构建方法,实际上构建的方案数就是最后新串的个数
我们可以模仿LCS的构建方法来思考这个问题 c[i][j]表示a串前i个元素和b串前j个元素所能得到的方案数。l[i][j]表示LCS的长度
若a[i]=b[j],那么c[i][j]=c[i-1][j-1],即a串前i-1个元素和b串前j-1个元素得到的组合串的末尾加上一个相同的元素a[i],那么得到的新的组合串的个数还是和之前的组合串的个数一样
若a[i]!=b[j], l[i][j]=max { l[i-1][j] , l[i][j-1]}
若l[i-1][j]>l[i][j-1],那说明从l[i-1][j]这种状态开始构建才能得到最终的LCS同时最终的组合串才不能漏掉共有的元素,所以c[i][i]=c[i-1][j],即在a串i-1个元素和b串j个元素组成的组合串的后面加上a[i],那么得到的新的组合串的个数和之前的组合串的个数是相同的
若l[i][j-1]>l[i-1][j],道理和上面是一样的,所以c[i][j]=c[i][j-1],相当于在之前的组合串后面加上元素b[j],得到新的组合串的个数不变
若l[i][j-1]=l[i-1][j],说明从两种状态都是能得到最终的LCS并且最终的组合串不会漏掉任何相同的公共元素,所以c[i][j]=c[i-1][j]+c[i][j-1] , 即用a串的i-1个元素和b串的j个元素组成的组合串的最后加上a[i]得到新的组合串和之前的组合串个数相同,另外用a串的i个元素和b串的的j-1个元素组成的组合串的最后加上b[j]得到新的组合串和之前的组合串个数相同,那么就是两者之和
另外读取a,b串的时候要用gets,就这样WA了两次
另外c[][]数组同long long
#include <stdio.h> #include <string.h> #define MAX 40 char a[MAX],b[MAX]; int l[MAX][MAX]; long long c[MAX][MAX]; int lena ,lenb; int main() { int T,t,i,j; scanf("%d",&T); getchar(); for(t=1; t<=T; t++) { gets(a+1); gets(b+1); //scanf("%s%s",a+1,b+1); lena=strlen(a+1); lenb=strlen(b+1); memset(l,0,sizeof(l)); memset(c,0,sizeof(c)); for(i=0; i<=lena; i++) c[i][0]=1; for(i=0; i<=lenb; i++) c[0][i]=1; for(i=1; i<=lena; i++) for(j=1; j<=lenb; j++) { if(a[i]==b[j]) { l[i][j]=l[i-1][j-1]+1; c[i][j]=c[i-1][j-1]; } else { if(l[i-1][j]>l[i][j-1]) { l[i][j]=l[i-1][j]; c[i][j]=c[i-1][j]; } else if(l[i][j-1]>l[i-1][j]) { l[i][j]=l[i][j-1]; c[i][j]=c[i][j-1]; } else { l[i][j]=l[i-1][j]; c[i][j]=c[i-1][j]+c[i][j-1]; } } } printf("Case #%d: %d %lld\n",t,lena+lenb-l[lena][lenb] , c[lena][lenb]); } return 0; }