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 }

 

posted @ 2019-02-28 09:52  jrltx  阅读(92)  评论(0编辑  收藏  举报