zoukankan      html  css  js  c++  java
  • 【Luogu】P3387缩点(Tarjan缩点+深搜DP)

     题没什么好说的,因为是模板题。求值我用的是dfs。

       不能直接在原图上dfs,因为原图上有环的话会发生一些滑稽的事情。所以我们要用Tarjan缩点。因为此题点权全为正,所以如果在图上走一个环当然可以全走一遍,结果当然是更优的。于是可以把环当成一个点来dfs,把它们的点权都加起来当成一个大点。

       然后就是求值。原图已经变成一张有向无环图,所以可以用拓扑排序求值,也可以枚举每个还没有被dfs到的点,然后dfs统计答案。dfs的时间是O(n),因为每个点最多被遍历一次。

       代码如下

    #include<cstdio>
    #include<cctype>
    #include<cstdlib>
    
    inline long long read(){
       long long num=0,f=1;
       char ch=getchar();
       while(!isdigit(ch)){
           if(ch=='-')f=-1;
           ch=getchar();
       }
       while(isdigit(ch)){
           num=num*10+ch-'0';
           ch=getchar();
       }
       return num*f;
    }
    
    struct Edge{
       int next,to;
    };
    struct Pic{
       Edge edge[200000];
       int head[100000],num;
       inline void add(int from,int to){
           edge[++num]=(Edge){head[from],to};
           head[from]=num;
       }
    }Old,New;
    int ans;
    int     f[150000];
    int   val[150000];
    int   que[150000];
    int   dfn[150000];
    int   low[150000];
    int   col[150000];
    bool  vis[150000];
    int stack[150000];
    int ID,top,cnt;
    void tarjan(int x){
       dfn[x]=low[x]=++ID;
       vis[x]=1;
       stack[++top]=x;
       for(int i=Old.head[x];i;i=Old.edge[i].next){
           int to=Old.edge[i].to;
           if(!dfn[to]){
               tarjan(to);
               low[x]=low[x]<low[to]?low[x]:low[to];
           }
           else if(vis[to])    low[x]=low[x]<dfn[to]?low[x]:dfn[to];
       }
       if(low[x]==dfn[x]){
           vis[x]=0;
           col[x]=++cnt;
           val[cnt]+=que[x];
           while(stack[top]!=x){
              col[stack[top--]]=cnt;
              val[cnt]+=que[stack[top+1]];
              vis[stack[top+1]]=0;
          }
          top--;
          }
    }
    
    int dfs(int x){
       if(f[x])return f[x];
       f[x]=val[x];
       int maxx=0;
       for(int i=New.head[x];i;i=New.edge[i].next){
           int to=New.edge[i].to;
           if(!f[to])dfs(to);
           maxx=maxx>f[to]?maxx:f[to];
       }
       f[x]+=maxx;
       return f[x];
    }
    
    int main(){
       int n=read(),m=read();
       for(int i=1;i<=n;++i)que[i]=read();
       int from,to;
       for(int i=1;i<=m;++i){
           from=read();to=read();
           Old.add(from,to);
       }
       for(int i=1;i<=n;++i)if(!dfn[i])tarjan(i);
       for(int i=1;i<=n;++i){
           for(int j=Old.head[i];j;j=Old.edge[j].next)    if(col[i]!=col[Old.edge[j].to])    New.add(col[i],col[Old.edge[j].to]);
       }
       for(int i=1;i<=cnt;++i)
           if(!f[i]){
               dfs(i);
               ans=ans>f[i]?ans:f[i];
           }
       printf("%d",ans);
    }
  • 相关阅读:
    javascript定义变量和优先级的问题
    css expression explaination
    apply()与call()详解
    jquery $(document).ready() 与window.onload的区别
    ES5严格模式
    css margin collapse
    作业 20181016-10 每周例行报告
    作业 20181009-9 每周例行报告
    作业 20180925-1 每周例行报告
    20180925-7 规格说明书-吉林市2日游
  • 原文地址:https://www.cnblogs.com/cellular-automaton/p/7467397.html
Copyright © 2011-2022 走看看