$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 }