容斥原理 进阶

2014/11/24


如果有两个字符串,让你求出它们的最长公共子序列。我想你们都会做的。
不过问题不仅限于此,WaKing还想让你告诉他,这两个字符串一共有多少个公共子序列,重复的不算。


输入:
输入两行每行一个字符串,为了使问题简单化,WaKing保证输入的字符在a~z之间,并且字符串的长度不超过50.
输出:
一行它们公共子序列的数量。
保证答案在int范围内。


样例输入:
asd
asd
ass
zas
样例输出:
7
3

题目是我自己编的,参照codevs上的容斥是三个字符串(有点....要用大数....就是diao。。)所以我这里把数据改弱了,直接int就能做,单纯的容斥,怕不怕?


同前文容斥原理一样,字符串两个的时候求公共子序列的数量

那么存在 dp[ i ][ j ] 表示 s1[ i ]  == s2[ j ];(不难理解,公共子序列的意义!)

dp[ i ][ j ] =2 * dp[ i -1][j-1]  -  dp[ ki - 1 ][ kj - 1 ];(s1[ ki ]  == s2[ kj ];)(想想为什么?单个字符串求子序列的时候的s[ i ] = 2*s[i-1 ] - s[k - 1])

容斥原理的本质都是在继承状态的过程中消去之前重复计算的一部分。


剩下的就是一些边界处理,初始化,以及 s[ i ] != s[ j ] 的时候的处理(状态继承)


#include<stdio.h>
#include<string.h>


int Max(int a,int b)
{
	return a>b?a:b;
}

char s1[55],s2[55];

int Dp[100][100];

int main()
{
		
   while(~scanf("%s%s",s1+1,s2+1))
   {
   	int len1 = strlen(s1+1);
   	int len2 = strlen(s2+1);

    memset(Dp,0,sizeof(Dp));
    
    
    for(int i = 0;i <= len1; i++)Dp[i][0] =1;
    for(int j = 0;j <= len2; j++)Dp[0][j] =1; 
    
    for(int i = 1;i <= len1; i++)
    for(int j = 1;j <= len2; j++)
    {
    	if(s1[i] == s2[j])
    	{
    		int ki = i - 1;while(s1[i]!=s1[ki]&&ki>0)ki--;
	    	int kj = j - 1;while(s2[j]!=s2[kj]&&kj>0)kj--;
	    	
	    	Dp[i][j] = 2*Dp[i-1][j-1];
	    	if(ki&&kj)Dp[i][j]-=Dp[ki-1][kj-1];	
	    }
	    else 
	    {
    		Dp[i][j] = Dp[i][j-1]+Dp[i-1][j]-Dp[i-1][j-1];//这里也是容斥,状态继承看你高中学的如何咯。
    	}
    }
   
   printf("%d\n",Dp[len1][len2] - 1);
   }
   return 0;	
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值