• POJ 3592 Instantaneous Transference(Tarjan缩点 + 记忆化搜索)


    题意:

    一辆坦克从 N*M 矩阵的左上角出发,每次往右或往 下走一格,每格可以是 '#' (表示不可以走), '*' 表示传送门,或者是数字,

    表示在该格可以获得的值(只能取一次),传送门可以传送到指定位置,你可以选择被传送或者走相邻的格,问坦克可以获得的值的和最大为多少。

    思路:

    1. 本题是由几个比较基本的问题组合而成的,关键的问题是在于建图,感谢前面几个网络流题目所培养的建图思想。

    2. 因为坦克只能往右下角的方向走,所以在满足条件的情况下,可以由 (i, j) 向 (i+1, j) or (i, j+1) 引弧。因为传送门的存在,还可以再引弧。

    3. 建图之后,由于传送门的存在可能会存在环,tarjan 算法化环为点,然后在单向图中记忆化搜索便可得出输出结果。

    #include <iostream>
    #include <stack>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    const int MAXN = 1610;
    vector<int> G[MAXN];
    vector<int> G1[MAXN];
    stack<int> S;
    int dfn[MAXN], low[MAXN], sccno[MAXN], sccnum, cflag;
    int row, col, F[MAXN], ore[MAXN], w[MAXN];
    char map[50][50];
    
    void tarjan(int u) {
        dfn[u] = low[u] = ++cflag;
        S.push(u);
        for (int i = 0; i < G[u].size(); i++) {
            int v = G[u][i];
            if (!dfn[v]) {
                tarjan(v);
                low[u] = min(low[u], low[v]);
            } else if (!sccno[v]) {
                low[u] = min(low[u], dfn[v]);
            }
        }
        if (low[u] == dfn[u]) {
            sccnum += 1;
            int v = -1;
            while (v != u) {
                v = S.top();
                S.pop();
                sccno[v] = sccnum;
                w[sccnum] += ore[v];
            }
        }
    }
    
    void findscc(int n) {
        for (int i = 0; i <= n; i++)
            dfn[i] = low[i] = sccno[i] = 0;
        sccnum = cflag = 0;
        for (int i = 1; i <= n; i++)
            if (!dfn[i]) tarjan(i);
    }
    
    int dp(int u) {
        if (F[u]) return F[u];
        F[u] = w[u];
        int x = 0;
        for (int i = 0; i < G1[u].size(); i++) {
            int v = G1[u][i];
            x = max(x, dp(v));
        }
        if (x) F[u] += x;
        return F[u];
    }
    
    inline int ID(int i, int j) { return i * col + j + 1; }
    
    int main() {
        int cases;
        scanf("%d", &cases);
        while (cases--) {
            scanf("%d%d", &row, &col);
    
            int n = ID(row - 1, col - 1);
            for (int i = 1; i <= n; i++)
                G[i].clear(), G1[i].clear();
    
            for (int i = 0; i < row; i++)
                scanf("%s", map[i]);
    
            for (int i = 0; i < row; i++) {
                for (int j = 0; j < col; j++) {
                    if (map[i][j] == '#') continue;
                    if (i + 1 < row && map[i+1][j] != '#')
                        G[ID(i, j)].push_back(ID(i+1, j));
                    if (j + 1 < col && map[i][j+1] != '#')
                        G[ID(i, j)].push_back(ID(i, j+1));
                    ore[ID(i, j)] = map[i][j] - '0';
                    if (map[i][j] == '*') {
                        int x, y;
                        scanf("%d%d", &x, &y);
                        if (map[x][y] != '#')
                            G[ID(i, j)].push_back(ID(x, y));
                        ore[ID(i, j)] = 0;
                    }
                }
            }
            for (int i = 0; i <= n; i++)
                F[i] = w[i] = 0;
            findscc(n);
            for (int u = 1; u <= n; u++) {
                for (int i = 0; i < G[u].size(); i++) {
                    int v = G[u][i];
                    if (sccno[u] != sccno[v]) 
                        G1[sccno[u]].push_back(sccno[v]);
                }
            }
            printf("%d\n", dp(sccno[ID(0, 0)]));
        }
        return 0;
    }
    -------------------------------------------------------

    kedebug

    Department of Computer Science and Engineering,

    Shanghai Jiao Tong University

    E-mail: kedebug0@gmail.com

    GitHub: http://github.com/kedebug

    -------------------------------------------------------

  • 相关阅读:
    hdu4276 依赖背包
    poj1155 依赖背包
    cf219d 基础换根法
    贪婪大陆——(树状数组)
    数星星(树状数组或者线段树)
    拓扑排序基础题——排序
    Codeforces Round #511 (Div. 1) T2 Little C Loves 3 II
    除虫药水(简单dp)
    烽火传递(单调队列优化dp,然而蒟蒻用一个优先队列做)
    ZOJ----3471Most powerful(简单状压dp)
  • 原文地址:https://www.cnblogs.com/kedebug/p/3073925.html
Copyright © 2020-2023  润新知