首页 > 其他 > 详细

P3387 【模板】缩点 [强连通分量][DAG]

时间:2020-01-20 22:31:22      阅读:79      评论:0      收藏:0      [点我收藏+]

题意

给定一个 \(n\) 个点 \(m\) 条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大。你只需要求出这个权值和。

允许多次经过一条边或者一个点,但是,重复经过的点,权值只计算一次

Solution

先缩点,就成了一个DAG图,做一遍拓扑排序,按拓扑序进行DP。

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 10010,M = 100010 * 2;
int head[N],ver[M],nxt[M],hc[N],vc[M],nc[M],tot,tc;
int ins[N],low[N],s[N],dfn[N],c[N],cnt,num,top,sum[N];
vector<int> scc[N];

void add(int x,int y){
    nxt[++tot] = head[x];
    ver[tot] = y;
    head[x] = tot;
}
void addc(int x,int y){
    nc[++tc] = hc[x];
    vc[tc] = y;
    hc[x] = tc;
}
void tarjan(int x){
    low[x] = dfn[x] = ++num;
    s[++top] = x; ins[x] = 1;
    for(int i = head[x]; i; i = nxt[i]){
        int v = ver[i];
        if(!dfn[v]){
            tarjan(v);
            low[x] = min(low[x],low[v]);
        }
        else if(ins[v])
            low[x] = min(low[x],dfn[v]);
    }
    if(low[x] == dfn[x]){
        cnt++; int y;
        do{
            y = s[top--]; ins[y] = 0;
            scc[cnt].push_back(y);
            c[y] = cnt;
        }while(x != y);
    }
}
int n,m,a[N],deg[N],dp[N];
void dfs(int x){
    dp[x] = sum[x];
    for(int i = hc[x]; i; i = nc[i]){
        int v = vc[i];
        dfs(v);
        dp[x] = max(dp[x],dp[v] + sum[x]);
    }
} 
int topo(){
    queue<int> q;
    for(int i = 1; i <= cnt; i++)
        if(!deg[i]) {
            q.push(i);
            dp[i] = sum[i];
        }
    while(!q.empty()){
        int x = q.front(); q.pop();
        for(int i = hc[x]; i; i = nc[i]){
            int y = vc[i];
            dp[y] = max(dp[y],dp[x] + sum[y]);
            deg[y]--;
            if(!deg[y]) 
                q.push(y);
        }
    }
    int ans = 0;
    for(int i = 1; i <= cnt; i++)
        ans = max(ans,dp[i]);
    return ans;
}

int main(){
    cin >> n >> m;
    for(int i = 1; i <= n; i++)
        cin >> a[i];
    for(int i = 1; i <= m; i++){
        int u,v;
        cin >> u >> v;
        add(u,v);
    }
    for(int i = 1; i <= n; i++)
        if(!dfn[i]) tarjan(i);
    for(int x = 1; x <= n; x++){
        for(int i = head[x]; i; i = nxt[i]){
            int v = ver[i];
            if(c[x] == c[v]) continue;
            addc(c[x],c[v]);
            deg[c[v]]++;
        }
    }
    for(int i = 1; i <= cnt; i++){
        for(int j = 0; j < scc[i].size(); j++)
            sum[i] += a[scc[i][j]];
    }
    cout << topo() << endl;
    return 0;
}

P3387 【模板】缩点 [强连通分量][DAG]

原文:https://www.cnblogs.com/FoxC/p/12219424.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!