• ZOJ-2366 Weird Dissimilarity 动态规划+贪心


    题意:现给定一个字符集中一共Z个元素的环境,给出一个Z*Z的数组,表示从i到j之间的距离。给定两组字符串,分别问包含着两个字符串(给定的字符串为所求字符串的子序列不是子串)对应位的距离和值最小为多少?输出这两个字符串。

    分析:该题的状态还是比较好开设的,设dp[i][j]表示a串的前i个字符和b串的前j个字符被包含后的最小开销,于是动态转移方程:

    dp[i][j] = min(dp[i][j], dp[i-1][j] + wa[sa[i]]);  其中wa数组表示某个字符与另外一个最小花费的字符匹配,sa[i]表示a串的第i个字符
    dp[i][j] = min(dp[i][j], dp[i][j-1] + wb[sb[j]]);  意义同上一个转移类似,均表示一个字符与一个最便宜的字符匹配
    dp[i][j] = min(dp[i][j], dp[i-1][j-1] + dist[sa[i]][sb[j]]);  该方程的意义为两个串均拿出一个字符来匹配

    这里需要说明的是补全两个串的最长长度最多为两个串长度之和,由上面的转移可以知道,每个位至少会有一个字符是属于串a或者是串b。

    还有一个地方要特别注意的是,给定字符集可能会有超过127的ascii码,并且编号之后可能有编号大于127,因此前面自己写的sa[i] = mp[sa[i]]一直RE就是出现了负数,改成了unsigned char了。

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    #include <iostream>
    #include <map>
    using namespace std;
    
    const int Z = 256;
    const int N = 2005;
    int d[Z][Z];
    map<char, int>mp;
    unsigned char str[Z], sa[N], sb[N];
    int na[N], nb[N];
    int la, lb, wa[Z], wb[Z], ca[Z], cb[Z];
    int idxa, idxb, dp[N][N], path[N][N];
    char qa[N<<1], qb[N<<1];
    // wa、wb数组分别用来说明sa串中的某字符的最佳匹配和sb串中某字符的最佳匹配
    // ca、cb数组记录在wa、wb数组取得最优解的情况下所对应的字符 
    
    void dfs(int i, int j) {
        if (!i && !j) return;
        if (i > 0 && j > 0 && dp[i][j] == dp[i-1][j-1] + d[sa[i]][sb[j]]) {
            qa[idxa++] = str[sa[i]];
            qb[idxb++] = str[sb[j]];
            dfs(i-1, j-1);
        } else if (i > 0 && dp[i][j] == dp[i-1][j] + wa[sa[i]]){
            qa[idxa++] = str[sa[i]];
            qb[idxb++] = str[ca[sa[i]]];
            dfs(i-1, j);
        } else {
            qa[idxa++] = str[cb[sb[j]]];
            qb[idxb++] = str[sb[j]];
            dfs(i, j-1);
        }
    }
    
    void gao() {
        // 最坏情况需要构造出长度为la+lb长度的串
        memset(dp, 0x3f, sizeof (dp));
        dp[0][0] = 0;
        for (int i = 0; i <= la; ++i) {
            for (int j = 0; j <= lb; ++j) {
                if (i > 0) {
                    dp[i][j] = min(dp[i][j], dp[i-1][j] + wa[sa[i]]);
                }
                if (j > 0) {
                    dp[i][j] = min(dp[i][j], dp[i][j-1] + wb[sb[j]]);
                }
                if (i > 0 && j > 0) {
                    dp[i][j] = min(dp[i][j], dp[i-1][j-1] + d[sa[i]][sb[j]]);
                }
            }
        }
        printf("%d
    ", dp[la][lb]);
        idxa = idxb = 0;
        dfs(la, lb);
        for (int i = idxa-1; i >= 0; --i) {
            putchar(qa[i]);
        }
        puts("");
        for (int i = idxb-1; i >= 0; --i) {
            putchar(qb[i]);
        }
        puts("");
    }
    
    int main() {
        int T;
        scanf("%d%", &T);
        while (T--) {
            mp.clear();
            memset(wa, 0x3f, sizeof (wa));
            memset(wb, 0x3f, sizeof (wb));
            scanf("%s", str+1);
            int len = strlen((char*)(str+1));
            for (int i = 1; i <= len; ++i) {
                mp[str[i]] = i;
            }
            scanf("%s %s", sa+1, sb+1);
            la = strlen((char *)(sa+1)), lb = strlen((char *)(sb+1));
            for (int i = 1; i <= la; ++i) {
                sa[i] = mp[sa[i]];
            }
            for (int i = 1; i <= lb; ++i) {
                sb[i] = mp[sb[i]];
            }
            for (int i = 1; i <= len; ++i) {
                for (int j = 1; j <= len; ++j) {
                    scanf("%d", &d[i][j]);
                    if (wa[i] > d[i][j]) {
                        wa[i] = d[i][j], ca[i] = j;
                    }
                    if (wb[j] > d[i][j]) {
                        wb[j] = d[i][j], cb[j] = i;
                    }
                }
            }
            gao();
        }
        return 0;
    }
  • 相关阅读:
    Harbor私有镜像仓库(下)
    项目课---企业级Memcached服务应用实践(八)
    项目课---OpVEN架构实施方案(七)
    项目课---Mha-Atlas-MySQL高可用方案实践(六)
    Nginx 反向代理
    Ansible搭建LNMP
    Ansible
    Ansible运维自动化
    JAVA企业级应用服务器之TOMCAT实战
    ssh自动分发密匙脚本样板
  • 原文地址:https://www.cnblogs.com/Lyush/p/3206645.html
Copyright © 2020-2023  润新知