zoukankan      html  css  js  c++  java
  • 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
    ",dp[len1][len2]);
    60     }
    61 
    62     return 0;
    63 }
    “这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。”
  • 相关阅读:
    中国石油大学天梯赛真题模拟第二场
    AtCoder Grand Contest 016 B
    POJ1011 Sticks
    UPC7817: Supermarket
    UPC5652: Ants on a Circle
    石大iCal课表使用指南
    UPC10582: Cowpatibility
    UPC11079: 小P的决斗 POJ3244 Difference between Triplets
    UPC6976:矩阵模板(二维哈希)
    知识点2-3:视图的职责
  • 原文地址:https://www.cnblogs.com/Blogggggg/p/7681170.html
Copyright © 2011-2022 走看看