UVA - 10723 Alibaba (dp)
给你两个长度不超过30的字符串序列,让你找到一个最短的字符串,使得给定的两个字符串均是它的子序列(不一定连续),求出最短长度以及符合条件的解的个数。
定义状态(a,b,c)为当前字符串长度为a,其中包含了第一个字符串的前b个字母和第二个字符串的前c个字母组成的子序列的状态
初始状态为(0,0,0),利用bfs刷表,直到刷出状态(?,l1,l2)为止(l1为一个个字符串的长度,l2同理)。由于要记录解的个数,所以要开一个数组siz,在刷状态的时候记录到达每个状态的不同方法的数量。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const ll N=30+5,inf=0x3f3f3f3f; 5 char s1[N],s2[N]; 6 ll siz[N*2][N][N],mi,cnt,ka; 7 struct D {ll a,b,c;}; 8 void bfs() { 9 mi=inf,cnt=0; 10 ll l1=strlen(s1),l2=strlen(s2); 11 queue<D> q; 12 memset(siz,0,sizeof siz); 13 siz[0][0][0]=1,q.push({0,0,0}); 14 while(!q.empty()) { 15 ll a=q.front().a,b=q.front().b,c=q.front().c; 16 q.pop(); 17 if(a>mi)continue; 18 if(b==l1&&c==l2) {mi=min(mi,a),cnt+=siz[a][b][c]; continue;} 19 for(ll i=0; i<24; ++i) { 20 ll aa=a+1,bb=b,cc=c; 21 if(s1[b]==i+'A')bb++; 22 if(s2[c]==i+'A')cc++; 23 if(!siz[aa][bb][cc])q.push({aa,bb,cc}); 24 siz[aa][bb][cc]+=siz[a][b][c]; 25 } 26 } 27 } 28 29 int main() { 30 ll T; 31 for(scanf("%lld",&T),getchar(); T--;) { 32 printf("Case #%lld: ",++ka); 33 gets(s1),gets(s2); 34 bfs(); 35 printf("%lld %lld\n",mi,cnt); 36 } 37 return 0; 38 }