$Tarjan$缩点

  Tarjan的第二个应用就是求缩点啦。缩点虽然比割点麻烦一点,但是用处也比割点要大不少。

  本来要学另外两个缩点算法的,但是似乎没什么用...$MST$里确实有只能有$prim$或者只能用$kruscal$的题目,但是这三种缩点...在网上没有找到介绍它们之间作用差异的文章,可能真的没有什么区别吧.

  缩点是对于有向图来说的。首先什么是强连通分量:里面的点两两之间互相可达。如果一道题中互相可达的点有某种神秘的联系(一个强连通分量等价于一个点的作用)时,就可以进行缩点。那么缩点有什么好处呢,显而易见的是可以快,把一些等价的点的操作一起做了,还有一个就是缩完点之后的图必然是一个$Dag$,可以在上面跑一些拓扑排序啊,$dp$啊之类的东西。  


  首先先看一个模板吧:

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

  题意概述:缩点后跑dp,求点权最大的路径,每个点的点权只算一次;

  
  1 # include <cstdio>
  2 # include <iostream>
  3 # define R register int
  4 
  5 using namespace std;
  6 
  7 int H,k,bp,cnt,h,Top=0,n,m,x,y,a[10009],firs[10009],Firs[10009],sta[10009];
  8 int id[10009],low[10009],vis[10009],A[10009];
  9 int dp[10009],color[10009],r[10009],q[100009];
 10 struct edge
 11 {
 12     int too,nex;
 13 }g[100009],G[100009];
 14 
 15 void add1(int x,int y)
 16 {
 17     g[++h].too=y;
 18     g[h].nex=firs[x];
 19     firs[x]=h;
 20 }
 21 
 22 void add2(int x,int y)
 23 {
 24     G[++H].too=y;
 25     G[H].nex=Firs[x];
 26     Firs[x]=H;
 27 }
 28 
 29 void dfs(int x)
 30 {
 31     low[x]=id[x]=++cnt;
 32     vis[x]=1;
 33     sta[++Top]=x;
 34     int j;
 35     for (R i=firs[x];i;i=g[i].nex)
 36     {
 37         j=g[i].too;
 38         if(!id[j])
 39         {
 40             dfs(j);
 41             low[x]=min(low[x],low[j]);
 42         }
 43         else
 44         {
 45             if(vis[j]) low[x]=min(low[x],low[j]);
 46         }
 47     }
 48     if(id[x]==low[x])
 49     {
 50         bp++;
 51         color[x]=bp;
 52         A[bp]+=a[x];
 53         vis[x]=0;
 54         while (sta[Top]!=x)
 55         {
 56             color[ sta[Top] ]=bp;
 57             A[bp]+=a[ sta[Top] ];
 58             vis[ sta[Top] ]=0;
 59             Top--;
 60         }
 61         Top--;
 62     }
 63 }
 64 
 65 int main()
 66 {
 67     scanf("%d%d",&n,&m);
 68     for (R i=1;i<=n;++i)
 69         scanf("%d",&a[i]);
 70     for (R i=1;i<=m;++i)
 71     {
 72         scanf("%d%d",&x,&y);
 73         add1(x,y);
 74     }
 75     for (R i=1;i<=n;++i)
 76         if(!id[i]) dfs(i);
 77     for (R i=1;i<=n;++i)
 78         for (R j=firs[i];j;j=g[j].nex)
 79         {
 80             k=g[j].too;
 81             if(color[i]!=color[k]) add2(color[i],color[k]),r[ color[k] ]++;
 82         }
 83     int num=0;
 84     for (R i=1;i<=bp;++i)
 85         if(!r[i]) q[++num]=i,dp[i]=A[i];
 86     for (R i=1;i<=num;++i)
 87     {
 88         for (R j=Firs[ q[i] ];j;j=G[j].nex)
 89         {
 90             k=G[j].too;
 91             r[k]--;
 92             dp[k]=max(dp[k],dp[ q[i] ]+A[k]);
 93             if(!r[k]) q[++num]=k;
 94         }
 95     }
 96     int ans=dp[1];
 97     for (R i=2;i<=bp;i++)
 98         ans=max(ans,dp[i]);
 99     cout<<ans;
100     return 0;
101 }
缩点

相关文章: