Tarjan&&縮點簡析
阿新 • • 發佈:2018-05-13
訪問 但是 while truct stat problem ems struct con
由於昨天寫計蒜客初賽的一道題,看出了是縮點,但一時忘記了另外一個叫什麽s...的算法怎麽寫了,話說我為什麽沒有回去翻一下自己的blog然後今天就去學了更實用也更強力的Tarjan
Tarjan的思想其實很簡單,就是用時間戳(講得真TM流弊,其實就是DFS訪問到的次序)和棧來搞一下
關於Tarjan的寫法,我自己也不是很講得來,大家可以看一下這篇blog
這裏講一下如何用Tarjan來進行縮點
令我們求出的col[i]表示原圖中第i個點是哪個強連通分量中的,則我們可以建出新圖,方式如下
for (i=1;i<=n;++i) for (j=head[i];j!=-1;j=e[j].next) if (col[i]!=col[e[j].to]) add(col[i],col[e[j].to]);
很玄學?但是它就是正確的,然後我們就得到了縮過點的新圖
像有這裏有一道模板題:Luogu P3387 【模板】縮點
題意很簡單,我們先Tarjan縮點,縮完的點的點權就是它這個強連通分量中的所有點的點權和
然後就是一個DAG(有向無環圖)了,我們DP,記搜,拓撲排序都可以
這裏我還是習慣性的寫了BFS的topo
CODE
#include<cstdio> #include<cstring> using namespace std; const int N=1e4+5,M=1e5+5; struct edge { int to,next; }e[M],ne[M]; int n,m,head[N],nhead[N],a[N],v[N],dfn[N],low[N],stack[N],col[N],dis[N],q[N],ru[N],top,cnt,x,y,tot,sum; bool vis[N]; inline char tc(void) { static char fl[100000],*A=fl,*B=fl; return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++; } inline void read(int &x) { x=0; char ch=tc(); while (ch<‘0‘||ch>‘9‘) ch=tc(); while (ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-‘0‘,ch=tc(); } inline void add(int x,int y) { e[++cnt].to=y; e[cnt].next=head[x]; head[x]=cnt; } inline void nadd(int x,int y) { ne[++cnt].to=y; ne[cnt].next=nhead[x]; nhead[x]=cnt; } inline int min(int a,int b) { return a<b?a:b; } inline int max(int a,int b) { return a>b?a:b; } inline void Tarjan(int now) { dfn[now]=low[now]=++tot; stack[++top]=now; vis[now]=1; for (register int i=head[now];i!=-1;i=e[i].next) if (!dfn[e[i].to]) { Tarjan(e[i].to); low[now]=min(low[now],low[e[i].to]); } else { if (vis[e[i].to]) low[now]=min(low[now],dfn[e[i].to]); } if (dfn[now]==low[now]) { col[now]=++sum; v[sum]+=a[now]; vis[now]=0; while (now!=stack[top]) { col[stack[top]]=sum; v[sum]+=a[stack[top]]; vis[stack[top--]]=0; } --top; } } inline int topo(void) { memset(dis,0,sizeof(dis)); register int i; int ans=0; int H=0,T=0; for (i=1;i<=sum;++i) if (!ru[i]) q[++T]=i,dis[i]=v[i],ans=max(dis[i],ans); while (H<T) { int now=q[++H]; for (i=nhead[now];i!=-1;i=ne[i].next) { dis[ne[i].to]=max(dis[ne[i].to],dis[now]+v[ne[i].to]); ans=max(ans,dis[ne[i].to]); if (!(--ru[ne[i].to])) q[++T]=ne[i].to; } } return ans; } int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); register int i,j; memset(head,-1,sizeof(head)); memset(e,-1,sizeof(e)); read(n); read(m); for (i=1;i<=n;++i) read(a[i]); for (i=1;i<=m;++i) read(x),read(y),add(x,y); for (i=1;i<=n;++i) if (!dfn[i]) Tarjan(i); memset(nhead,-1,sizeof(head)); memset(ne,-1,sizeof(e)); cnt=0; for (i=1;i<=n;++i) for (j=head[i];j!=-1;j=e[j].next) if (col[i]!=col[e[j].to]) nadd(col[i],col[e[j].to]),++ru[col[e[j].to]]; printf("%d",topo()); return 0; }
Tarjan&&縮點簡析