UVA1625

题目大意:

  给出两个字符串,其中只有 ‘A' ~ 'Z' 这26个英文字母。定义 L(G)= 字符 'G' 在一个字符串中第一次出现的位置减去最后一次出现的位置。按顺序组合给出的连个字符串(例:"ABC" 和 “DEF" 可以组合为 "ABCDEF" 或 “ADBECF",即在组合出来的字符串中的给出的两个子串自己顺序不能乱),求 SUM_OF_L 的最小值。

解题思路:

  先预处理出 have[i][j] = 当把第一个字符串中的前 i 个字母和第二个字符串中的前 j 个字母放在一起以后有多少个字母已经 “开始” 但还没有 “结束” (“结束” 是指后面已经没有这个字母了),那么不难得出状态转移方程 dp[i][j] = min(dp[i-1][j]+have[i-1][j], dp[i][j-1]+have[i][j-1]),其中 dp[i][j] = 当把第一个字符串中的前 i 个字母和第二个字符串中的前 j 个字母放在一起以后 SUM_OF_L 的最小值,相信读者不难发现这部分很像最长公共子序列,对吧?

  那么现在的问题就只剩下如何预处理出 have[i][j],其实也不难,记录下各个字符串中的各个字母第一次出现和最后一次出现的位置,然后每一个 have[i][j] 都在 have[i][j-1] 的基础上更新即可。

AC代码:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 
 6 using namespace std;
 7 const int maxn=5003;
 8 char s1[maxn],s2[maxn];
 9 int dic[3][30][2];
10 int dp[maxn][maxn],have[maxn][maxn];
11 int main(){
12   //  freopen("IN.txt","r",stdin);
13     int T;
14     scanf("%d",&T);
15     while(T--){
16         memset(dic,0,sizeof(dic));
17         scanf("%s",s1+1);   int len1=strlen(s1+1);
18         scanf("%s",s2+1);   int len2=strlen(s2+1);
19         for(int i=0;i<=len1;i++){
20             for(int j=0;j<=len2;j++)    dp[i][j]=have[i][j]=0;
21         }
22         for(int i=1;i<=len1;i++){
23             if(dic[1][s1[i]-'A'][0]==0){
24                 dic[1][s1[i]-'A'][0]=i;
25             }
26             dic[1][s1[i]-'A'][1]=i;
27         }
28         for(int i=1;i<=len2;i++){
29             if(dic[2][s2[i]-'A'][0]==0){
30                 dic[2][s2[i]-'A'][0]=i;
31             }
32             dic[2][s2[i]-'A'][1]=i;
33         }
34         for(int i=1;i<=len1;i++){
35             have[i][0]=have[i-1][0];
36             if(dic[1][s1[i]-'A'][0]==i) have[i][0]++;
37             if(dic[1][s1[i]-'A'][1]==i&&dic[2][s1[i]-'A'][0]==0) have[i][0]--;
38         }
39         for(int i=1;i<=len2;i++){
40             have[0][i]=have[0][i-1];
41             if(dic[2][s2[i]-'A'][0]==i) have[0][i]++;
42             if(dic[2][s2[i]-'A'][1]==i&&dic[1][s2[i]-'A'][0]==0) have[0][i]--;
43         }
44         for(int i=1;i<=len1;i++){
45             for(int j=1;j<=len2;j++){
46                 have[i][j]=have[i][j-1];
47                 if(dic[1][s2[j]-'A'][1]<=i && dic[2][s2[j]-'A'][1]<=j)  have[i][j]--;
48                 if((dic[1][s2[j]-'A'][0]==0||dic[1][s2[j]-'A'][0]>i)
49                    &&(dic[2][s2[j]-'A'][0]==0||dic[2][s2[j]-'A'][0]>=j))    have[i][j]++;
50             }
51         }
52         for(int i=1;i<=len1;i++)    dp[i][0]=dp[i-1][0]+have[i-1][0];
53         for(int j=1;j<=len2;j++)    dp[0][j]=dp[0][j-1]+have[0][j-1];
54         for(int i=1;i<=len1;i++){
55             for(int j=1;j<=len2;j++){
56                 dp[i][j]=min(dp[i-1][j]+have[i-1][j],dp[i][j-1]+have[i][j-1]);
57             }
58         }
59         printf("%d\n",dp[len1][len2]);
60     }
61 
62     return 0;
63 }

 

posted @ 2017-10-17 13:34  Blogggggg  阅读(202)  评论(2编辑  收藏  举报