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;
    }
    
  • 相关阅读:
    年底送书活动:送出6本技术书籍,价值372元!
    (7)ASP.NET WEB服务器控件
    (6)DataTable 转换成 Json
    (9)C#连mysql
    (8)C#连sqlserver
    VM虚拟机
    (7)C#连DB2---oledb方式
    (48)C#网络4 web
    远程桌面
    (47)C#运行时序列化
  • 原文地址:https://www.cnblogs.com/streamazure/p/13820627.html
Copyright © 2011-2022 走看看