zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    遍历二维数组
    冒泡跟扫描共用
    1.8作业
    1.7作业
    1.5作业
    百文百鸡 水仙花数 百马百担
    for循环输出九九乘法表
    循环语句
    1.4作业
    07、找出1-99之间的同构数
  • 原文地址:https://www.cnblogs.com/shaokele/p/9354713.html
Copyright © 2011-2022 走看看