luoguP3387 【模板】缩点

www.cnblogs.com/shaokele/


luoguP3387 【模板】缩点##

  Time Limit: 1 Sec
  Memory Limit: 128 MB

Description###

  给定一个n个点m条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大。你只需要求出这个权值和。
  允许多次经过一条边或者一个点,但是,重复经过的点,权值只计算一次。
 

Input###

  第一行,n,m
  
  第二行,n个整数,依次代表点权
  
  第三至m+2行,每行两个整数u,v,表示u->v有一条有向边
 

Output###

  共一行,最大的点权之和。
 

Sample Input###

  2 2
  
  1 1
  
  1 2
  
  2 1
 

Sample Output###

  2
  

HINT###

  n<=104,m<=105,点权<=1000
  
  算法:Tarjan缩点+DAGdp

题目地址:  luoguP3387 【模板】缩点

题目大意: 模板题

题解:

  Tarjan缩点模板题


AC代码

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=1e4+5,M=1e5+5;
int n,m,num,top,tot,ans,cnt1,cnt2;
int a[N],dfn[N],low[N],s[N],sum[N],col[N],f[N],in[N];
int last1[N],last2[N];
bool ins[N];
int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
struct edge1{
    int to,next;
}e1[M<<1];
struct edge2{
    int to,next;
}e2[M<<1];
void add_edge1(int u,int v){
    e1[++cnt1]=(edge1){v,last1[u]};last1[u]=cnt1;
}
void add_edge2(int u,int v){
    e2[++cnt2]=(edge2){v,last2[u]};last2[u]=cnt2;
}
void Tarjan(int u){
    dfn[u]=low[u]=++tot;
    s[++top]=u;ins[u]=1;
    for(int i=last1[u];i;i=e1[i].next){
        int v=e1[i].to;
        if(!dfn[v]){
            Tarjan(v);
            low[u]=min(low[u],low[v]);
        }else if(ins[v])
            low[u]=min(low[u],dfn[v]);
    }
    if(dfn[u]==low[u]){
        num++;
        while(s[top]!=u){
            sum[num]+=a[s[top]];
            col[s[top]]=num;
            ins[s[top--]]=0;
        }
        sum[num]+=a[s[top]];
        col[s[top]]=num;
        ins[s[top--]]=0;
    }
}
void dp(int u,int fa){
    f[u]=sum[u];
    for(int i=last2[u];i;i=e2[i].next){
        int v=e2[i].to;
        if(v==fa)continue;
        dp(v,u);
        f[u]=max(f[u],f[v]+sum[u]);
    }
}
int main(){
    n=read();m=read();
    for(int i=1;i<=n;i++)a[i]=read();
    for(int i=1;i<=m;i++){
        int u=read(),v=read();
        add_edge1(u,v);
    }
    for(int i=1;i<=n;i++)
        if(dfn[i]==0)Tarjan(i);
    for(int u=1;u<=n;u++)
        for(int i=last1[u];i;i=e1[i].next){
            int v=e1[i].to;
            if(col[u]!=col[v]){
                add_edge2(col[u],col[v]);
                in[col[v]]++;
            }
        }
    for(int i=1;i<=num;i++)
        if(in[i]==0){
            dp(i,0);
            ans=max(ans,f[i]);
        }
    printf("%d
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/shaokele/p/9354713.html