zoukankan      html  css  js  c++  java
  • UVA

    UVA - 1625
    Download as PDF
     

    白书
    很明显f[i][j]表示第一个取到i第二个取到j的代价
    问题在于代价的计算,并不知道每种颜色的开始和结束
     
    和模拟赛那道环形DP很想,计算这次转移会给其他的元素带来的代价,也就是转移前已经出现但还没结束的元素都会代价+1
     
    预处理每种颜色在两个序列中出现的位置bg[i][0/1]和ed[i][0/1],
    计算f[i][j]时同时计算w[i][j]为(i,j)这个状态已经出现还没结束的个数
    注意bg要先初始化为INF,计算w:
    if(bg[c][0]==i&&bg[c][1]>j) w[i][j]++;
    if(ed[c][0]==i&&ed[c][1]<=j) w[i][j]--;
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #include <queue>
    using namespace std;
    typedef long long ll;
    const int N=5005,INF=1e9;
    int T,n,m;
    char a[N],b[N];
    int f[N][N],w[N][N],bg[27][2],ed[27][2];
    void dp(){
        memset(bg,0,sizeof(bg));
        memset(ed,0,sizeof(ed));
        for(int i=0;i<26;i++) bg[i][0]=bg[i][1]=INF;
        for(int i=1;i<=n;i++){
            int c=a[i]-'A';
            if(bg[c][0]==INF) bg[c][0]=i;
            ed[c][0]=i;
        }
        for(int i=1;i<=m;i++){
            int c=b[i]-'A';
            if(bg[c][1]==INF) bg[c][1]=i;
            ed[c][1]=i;
        }
        for(int i=0;i<=n;i++)
            for(int j=0;j<=m;j++){
                //f[i][j]=min(f[i-1][j]+cal(i-1,j),f[i][j-1]+cal(i,j-1));
                //f[i][j]=min(f[i-1][j],f[i][j-1])+cal(i,j);
                if(i==0&&j==0) continue;
                int t1=INF,t2=INF;
                if(i>0) t1=f[i-1][j]+w[i-1][j];
                if(j>0) t2=f[i][j-1]+w[i][j-1];
                f[i][j]=min(t1,t2);
                
                if(i>0){
                    w[i][j]=w[i-1][j];
                    int c=a[i]-'A';
                    if(bg[c][0]==i&&bg[c][1]>j) w[i][j]++;
                    if(ed[c][0]==i&&ed[c][1]<=j) w[i][j]--;
                }else{
                    w[i][j]=w[i][j-1];
                    int c=b[j]-'A';
                    if(bg[c][1]==j&&bg[c][0]>i) w[i][j]++;
                    if(ed[c][1]==j&&ed[c][0]<=i) w[i][j]--;
                    //if(b[j]=='R') printf("R %d %d %d %d
    ",bg[c][1],ed[c][1],i,j);
                }
                //printf("%d %d %d %d
    ",i,j,f[i][j],w[i][j]);
            }
    }
    int main(){
        scanf("%d",&T);
        while(T--){
            scanf("%s%s",a+1,b+1);
            n=strlen(a+1);m=strlen(b+1);
            dp();
            printf("%d
    ",f[n][m]);
        }
    }

    白书的标程用了滚动数组,可以借鉴一下

    // UVa1625 Color Length
    // Rujia Liu
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    const int maxn = 5000 + 5;
    const int INF = 1000000000;
    
    char p[maxn], q[maxn]; // starts from position 1
    int sp[26], sq[26], ep[26], eq[26]; // sp[i] start positions of character i in p
    int d[2][maxn], c[2][maxn]; // 滚动数组 c[i][j]: how many "incomplete" colors in the mixed sequence
    
    int main()
    {
        int T;
        scanf("%d", &T);
        while(T--)
        {
            scanf("%s%s", p+1, q+1);
    
            int n = strlen(p+1);
            int m = strlen(q+1);
            for(int i = 1; i <= n; i++) p[i] -= 'A';
            for(int i = 1; i <= m; i++) q[i] -= 'A';
    
            // calculate s and e
            for(int i = 0; i < 26; i++)
            {
                sp[i] = sq[i] = INF;
                ep[i] = eq[i] = 0;
            }
            for(int i = 1; i <= n; i++)
            {
                sp[p[i]] = min(sp[p[i]], i);
                ep[p[i]] = i;
            }
            for(int i = 1; i <= m; i++)
            {
                sq[q[i]] = min(sq[q[i]], i);
                eq[q[i]] = i;
            }
    
            // dp
            int t = 0;
            memset(c, 0, sizeof(c));
            memset(d, 0, sizeof(d));
            for(int i = 0; i <= n; i++)
            {
                for(int j = 0; j <= m; j++)
                {
                    if(!i && !j) continue;
    
                    // calculate d
                    int v1 = INF, v2 = INF;
                    //计算d[i][j],  d[i][j]由d[i-1][j]或d[i][j-1]添加一个字母得到
                    if(i) v1 = d[t^1][j] + c[t^1][j]; // remove from p
                    if(j) v2 = d[t][j - 1] + c[t][j - 1]; // remove from q
                    d[t][j] = min(v1, v2);
    
                    // calculate c
                    if(i)
                    {
                        c[t][j] = c[t^1][j];
                        if(sp[p[i]] == i && sq[p[i]] > j) c[t][j]++;            //出现新的字母
                        if(ep[p[i]] == i && eq[p[i]] <= j) c[t][j]--;           //一个字母已经结束
                    }
                    else if(j)
                    {
                        c[t][j] = c[t][j - 1];
                        if(sq[q[j]] == j && sp[q[j]] > i) c[t][j]++;
                        if(eq[q[j]] == j && ep[q[j]] <= i) c[t][j]--;
                    }
                }
                t ^= 1;
            }
            printf("%d
    ", d[t^1][m]);
        }
        return 0;
    }
  • 相关阅读:
    浅谈常量
    运算符
    TTL与CMOS门电路
    16位CRC校验_Delphi
    DXP快捷键记录(红色为经常用到的)
    论EFMS模拟量部分采集电路的修改
    稳压二极管应用电路_转载
    TVS二极管
    TryEnterCriticalSection___Delphi
    很好用的一个翻译插件
  • 原文地址:https://www.cnblogs.com/candy99/p/5985217.html
Copyright © 2011-2022 走看看