洛谷3387:【模板】缩点——题解

https://www.luogu.org/problemnew/show/P3387

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

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

有环我们很不好判断,但是显然在一个强连通分量里面的点我们都可以到达。

所以缩起来之后就是一个DAG,之后随便你怎么算都行(bfs/dfs)

(我觉得并不算是dp emmm)

#include<stack>
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1e4+5;
const int M=1e5+5;
inline int read(){
    int x=0,w=1;char ch=0;
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*w;
}
struct node{
    int w,to,nxt;
}e[2][M];
int cnt,h[2][N];
inline void add(int u,int v,int k){
    e[k][++cnt].to=v;e[k][cnt].nxt=h[k][u];h[k][u]=cnt;
}
int dfn[N],low[N],val[N],to[N],sum[N],f[N],indeg[N],t,l;
stack<int>q;
queue<int>p;
bool inq[N],vis[N];
void tarjan(int u){
    int v;
    dfn[u]=low[u]=++t;
    q.push(u);inq[u]=1;
    for(int i=h[0][u];i;i=e[0][i].nxt){
    v=e[0][i].to;
    if(!dfn[v]){
        tarjan(v);
        low[u]=min(low[u],low[v]);
    }else if(inq[v]){
        low[u]=min(low[u],dfn[v]);
    }
    }
    if(dfn[u]==low[u]){
    l++;
    do{
        v=q.top();
        q.pop();
        inq[v]=0;
        to[v]=l;
        sum[l]+=val[v];
    }while(v!=u);
    }
}
void bfs(int u){
    vis[u]=1;f[u]=sum[u];
    p.push(u);
    while(!p.empty()){
    u=p.front();p.pop();vis[u]=0;
    for(int i=h[1][u];i;i=e[1][i].nxt){
        int v=e[1][i].to;
        if(f[v]<f[u]+sum[v]){
        f[v]=f[u]+sum[v];
        if(!vis[v]){
            vis[v]=1;
            p.push(v);
        }
        }
    }
    }
}
int main(){
    int n=read(),m=read();
    for(int i=1;i<=n;i++)val[i]=read();
    for(int i=1;i<=m;i++){
    int u=read(),v=read();
    add(u,v,0);
    }
    for(int i=1;i<=n;i++){
    if(!dfn[i])tarjan(i);
    }
    for(int u=1;u<=n;u++){
    for(int j=h[0][u];j;j=e[0][j].nxt){
        int v=to[e[0][j].to];
        bool link=0;
        for(int k=h[1][to[u]];k&&!link;k=e[1][k].nxt){
        int w=e[1][k].to;
        if(v==w)link=1;
        }
        if(!link&&to[u]!=v){
        add(to[u],v,1);
        indeg[v]++;
        }
    }
    }
    memset(f,-127,sizeof(f));
    for(int i=1;i<=l;i++){
    if(!indeg[i]){
        bfs(i);
    }
    }
    int ans=0;
    for(int i=1;i<=l;i++)ans=max(ans,f[i]);
    printf("%d\n",ans);
    return 0;
}

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

posted @ 2018-04-02 19:51  luyouqi233  阅读(242)  评论(0编辑  收藏  举报