• C. Dasha and Password 预处理 + dp


    http://codeforces.com/contest/761/problem/C

    对于每一个字符串,可以预处理出其到达数字,字母,和特殊符号所需的最小步数。

    然后就是在n个东西中,选出数字、字母和特殊符号,至少一个,所需的最少步数。

    因为第一个选了数字的话,它就不能选字母的了,然后比赛的时候发现这就是二分图,然后就上了km的模板。(太笨了我)

    虽然过了,但是明显正解不是这个。

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <assert.h>
    #define IOS ios::sync_with_stdio(false)
    using namespace std;
    #define inf (0x3f3f3f3f)
    typedef long long int LL;
    
    
    #include <iostream>
    #include <sstream>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #include <bitset>
    const int maxn = 500 + 20;
    char str[maxn][maxn];
    int e[200 + 20][200 + 20];
    
    
    int match[maxn];//match[col] = row
    int vx[maxn], vy[maxn];
    int fx[maxn], fy[maxn];
    int dfs (int u, int m) {
        vx[u] = 1;
        int i;
        for (i = 1; i <= m; i++) { //筛选n个 导航员 col的值
            if (vy[i] == 0 && fx[u] + fy[i] == e[u][i]) {
                vy[i] = 1;
                if (match[i] == 0 || dfs(match[i], m)) {
                    match[i] = u; // match[col]=row;
                    return 1;//搭配成功
                }
            }
        }
        return 0;//我找不到啊,后面,就会执行km
    }
    void do_km(int n, int m) { //
        int i, j;
        int d = -inf;
        for (i = 1; i <= n; i++) { //遍历每一个驾驶员 row的值
            if (vx[i] == 1) {
                for (j = 1; j <= m; j++) { //对他进行遍历导航员 col的值
                    if (!vy[j]) {
                        if (d < (fx[i] + fy[j] - e[i][j])) {
                            d = fx[i] + fy[j] - e[i][j];
                        }
                    }
                }
            }
        }
        for (i = 1; i <= n; i++) {
            if (vx[i] == 1) {
                fx[i] -= d;
                vx[i] = 0; //请0
            }
            if (vy[i] == 1) { //
                fy[i] += d;
                vy[i] = 0; //情0
            }
        }
        return ;
    }
    int anskm(int n, int m) {
        memset(vx, 0, sizeof(vx));
        memset(vy, 0, sizeof(vy));
        memset(fx, 0, sizeof(fx));
        memset(fy, 0, sizeof(fy));
        memset(match, 0, sizeof(match));
        //km算法的一部分,先初始化fx,fy
        for (int i = 1; i <= n; i++) { //遍历每一个驾驶员 row的值
            fy[i] = 0;
            fx[i] = inf; //无穷小
            for (int j = 1; j <= m; j++) { //遍历每一个导航员 col的值
                if (fx[i] > e[i][j]) { //默契值
                    fx[i] = e[i][j];
                }
            }
        }
        for (int i = 1; i <= n; i++) { //遍历每一个驾驶员 row的值
            memset(vx, 0, sizeof(vx));
            memset(vy, 0, sizeof(vy));
            while (!dfs(i, m)) {//如果他找不到搭配,就实现km算法
                do_km(n, m);//km完后,还是会对这个想插入的节点进行dfs的,因为他还没搭配嘛
            }
        }
        int ans = 0;
        for (int i = 1; i <= m; i++) //遍历导航员,col的值
            ans += e[match[i]][i];//输入的row是驾驶员,col是导航员
        //match[i]:导航员i和驾驶员match[i]搭配了              match[col]=row;
        return ans;
    }
    
    
    
    void work() {
        int n, m;
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= 200; ++i) {
            for (int j = 1; j <= 200; ++j) {
                e[i][j] = 500;
            }
        }
        for (int i = 1; i <= n; ++i) {
            scanf("%s", str[i] + 1);
            int a = 500, b = 500, c = 500;
            int len = m;
            for (int j = 1; str[i][j]; ++j) {
                if (str[i][j] >= '0' && str[i][j] <= '9') {
                    a = min(a, j - 1);
                } else if (str[i][j] == '#' || str[i][j] == '*' || str[i][j] == '&') {
                    b = min(b, j - 1);
                } else {
                    c = min(c, j - 1);
                }
            }
            for (int j = len; j >= 1; j--) {
                if (str[i][j] >= '0' && str[i][j] <= '9') {
                    a = min(a, len - j + 1);
                } else if (str[i][j] == '#' || str[i][j] == '*' || str[i][j] == '&') {
                    b = min(b, len - j + 1);
                } else {
                    c = min(c, len - j + 1);
                }
            }
            e[i][1] = a;
            e[i][2] = b;
            e[i][3] = c;
        }
    //    for (int i = 1; i <= n; ++i) {
    //        for (int j = 1; j <= n; ++j) {
    //            cout << e[i][j] << " ";
    //        }
    //        cout << endl;
    //    }
        cout << anskm(n, n) - (n - 3) * 500 << endl;
    }
    
    int main() {
    #ifdef local
        freopen("data.txt", "r", stdin);
    //    freopen("data.txt", "w", stdout);
    #endif
        work();
        return 0;
    }
    km

    正解因该是一个dp

    dp[i][2][2]][2]表示在前i个字符串中,选出了数字(0 or 1)、字母、特殊符号所需的最小步数。

    转移

    dp[now][a][b][c] = min(dp[now][a][b][c], dp[!now][a][b][c]); //保留上次的最小值。

    然后对于每一个a、b、c

    dp[now][a][b][c] = min(dp[now][a][b][c], dp[!now][a - 1][b][c] + e[i][1]);之类的。

    一开始还担心会不会使得同一个字符串,既选了数字,也选了字母。

    然后是不会的,因为需要选数字的时候,是从dp[!now][a - 1][b][c]转移过来的,也就是从上一唯的b、c转过来。所以不会有重复。

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <assert.h>
    #define IOS ios::sync_with_stdio(false)
    using namespace std;
    #define inf (0x3f3f3f3f)
    typedef long long int LL;
    
    
    #include <iostream>
    #include <sstream>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #include <bitset>
    const int maxn = 500 + 20;
    char str[maxn][maxn];
    int e[200 + 20][200 + 20];
    int dp[2][2][2][2];
    void work() {
        int n, m;
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= 200; ++i) {
            for (int j = 1; j <= 200; ++j) {
                e[i][j] = 500;
            }
        }
        for (int i = 1; i <= n; ++i) {
            scanf("%s", str[i] + 1);
            int a = 500, b = 500, c = 500;
            int len = m;
            for (int j = 1; str[i][j]; ++j) {
                if (str[i][j] >= '0' && str[i][j] <= '9') {
                    a = min(a, j - 1);
                } else if (str[i][j] == '#' || str[i][j] == '*' || str[i][j] == '&') {
                    b = min(b, j - 1);
                } else {
                    c = min(c, j - 1);
                }
            }
            for (int j = len; j >= 1; j--) {
                if (str[i][j] >= '0' && str[i][j] <= '9') {
                    a = min(a, len - j + 1);
                } else if (str[i][j] == '#' || str[i][j] == '*' || str[i][j] == '&') {
                    b = min(b, len - j + 1);
                } else {
                    c = min(c, len - j + 1);
                }
            }
            e[i][1] = a;
            e[i][2] = b;
            e[i][3] = c;
        }
        memset(dp, 0x3f, sizeof dp);
        int now = 0;
        dp[now][0][0][0] = 0;
        for (int i = 1; i <= n; ++i) {
            now = !now;
            for (int a = 0; a <= 1; ++a) {
                for (int b = 0; b <= 1; ++b) {
                    for (int c = 0; c <= 1; ++c) {
                        dp[now][a][b][c] = min(dp[now][a][b][c], dp[!now][a][b][c]);
                        if (a) {
                            dp[now][a][b][c] = min(dp[now][a][b][c], dp[!now][a - 1][b][c] + e[i][1]);
    //                        break;
                        }
                        if (b) {
                            dp[now][a][b][c] = min(dp[now][a][b][c], dp[!now][a][b - 1][c] + e[i][2]);
    //                        break;
                        }
                        if (c) {
                            dp[now][a][b][c] = min(dp[now][a][b][c], dp[!now][a][b][c - 1] + e[i][3]);
    //                        break;
                        }
                    }
                }
            }
        }
        cout << dp[now][1][1][1] << endl;
    }
    
    int main() {
    #ifdef local
        freopen("data.txt", "r", stdin);
    //    freopen("data.txt", "w", stdout);
    #endif
        work();
        return 0;
    }
    View Code
  • 相关阅读:
    vim how to set nu with 0-index instead of 1-index
    @property的介绍与使用
    X[:,0]和X[:,1]
    the best guide for git
    sorted(列表)
    Java的匿名函数
    成员变量和局部变量的区别
    Java数组合并
    Java中random的使用
    Git常见错误---git branch不显示本地分支的问题
  • 原文地址:https://www.cnblogs.com/liuweimingcprogram/p/6359892.html
Copyright © 2020-2023  润新知