zoukankan      html  css  js  c++  java
  • 【SCC缩点+DAGdp】P1137 旅行计划

    P1137 旅行计划

    思路:缩点+DAGdp,与模板有所区别的是,本题求的是“以节点(i)终点的最长路”。将缩点之后的新图反向建边,即可直接用“以节点(i)为起点的最长路”的DAGdp。

    #define mem(a,n) memset(a,n,sizeof(a))
    #define f(i,a,b) for(int i=a;i<=b;i++)
    #define af(i,a,b) for(int i=a,i>=b;i--)
    
    using namespace std;
    typedef long long LL;
    const int INF = 20010509;
    const int maxn = 1e5 + 100;
    const int maxm = 2e5 + 100;
    
    stack<int> s;
    
    int dfs_clock, scc_cnt;
    int dfn[maxn], low[maxn], sccno[maxn];
    int head[maxn], headnew[maxn], cnt = 0;
    int n, m;
    int dp[maxn];
    int val_new[maxn];
    
    struct Edge {
        int from,next, to;
    }e[maxm], enew[maxm];
    
    void add(int from, int to, Edge eset[], int head[]) {
        cnt++;
        eset[cnt].from = from;
        eset[cnt].next = head[from];
        eset[cnt].to = to;
        head[from] = cnt;
    }
    
    void dfs(int u) {
        dfn[u] = low[u] = ++dfs_clock;
        s.push(u);
        for (int i = head[u]; i; i = e[i].next) {
            int v = e[i].to;
            if (!dfn[v]) {
                dfs(v);
                low[u] = min(low[u], low[v]);
            }
            else if (!sccno[v]) {
                low[u] = min(low[u], dfn[v]);
            }
        }
        if (low[u] == dfn[u]) {
            scc_cnt++;
            while (1) {
                int x = s.top(); s.pop();
                sccno[x] = scc_cnt;
                val_new[sccno[x]] ++;
                if (x == u) break;
            }
        }
    }
    
    void find_scc(int n) {
        while (!s.empty()) s.pop();
        dfs_clock = scc_cnt = 0;
        mem(sccno, 0);
        mem(dfn, 0);
        mem(low, 0);
        for (int i = 1; i <= n; i++) {
            if (!dfn[i]) dfs(i);
        }
    }
    
    //dp[i]:=以节点i为终点的最长路
    //dp[j]=max(dp[i],dp[j])(其中j满足:存在i→j的有向边)
    
    int Dp(int i) {
        if (dp[i]) return dp[i];
        dp[i] = val_new[i];
        for (int j = headnew[i]; j; j = enew[j].next) {
            int v = enew[j].to;
            dp[i] = max(dp[i], Dp(v) + val_new[i]);
        }
        return dp[i];
    }
    
    int main(){
        cnt = 0;
        cin >> n >> m;
        for (int i = 1; i <= m; i++) {
            int u, v; cin >> u >> v;
            add(u, v, e, head);
        }
        find_scc(n);
        cnt = 0;
        //将SCC都缩成一个点,建立新图
        for (int u = 1; u <= n; u++) {
            for (int i = head[u]; i; i = e[i].next) {
                int v = e[i].to;
                if (sccno[u] != sccno[v]) {
                   add(sccno[v], sccno[u], enew, headnew);
                   //反向建图,dp时按“dp[i]:=以i为起点的最长路”dp
                }
            }
        }
        
        //以每个城市作为终点
        for (int i = 1; i <= n; i++) {
            cout << Dp(sccno[i]) << endl;
        }
        return 0;
    }
    
  • 相关阅读:
    Mayan游戏 (codevs 1136)题解
    虫食算 (codevs 1064)题解
    靶形数独 (codevs 1174)题解
    黑白棋游戏 (codevs 2743)题解
    神经网络 (codevs 1088) 题解
    The Rotation Game (POJ 2286) 题解
    倒水问题 (codevs 1226) 题解
    银河英雄传说 (codevs 1540) 题解
    生日蛋糕 (codevs 1710) 题解
    第一章 1.11 高阶函数
  • 原文地址:https://www.cnblogs.com/streamazure/p/13820627.html
Copyright © 2011-2022 走看看