tarjan缩点——在农场万圣节Trick or Treat on the Farm
作者:互联网
一个房间能到另一个房间,有向图,奶牛从自己编号(1到n)的点出发,如果回到以前到过的点就停止,问每头奶牛可以经过几个点;
情况分两种,
一,奶牛在环上,能走的是环的大小,二,一条链连接一个环,大小是链+环;
要预先处理自环的答案(1),还有环的大小是1的(并不在环上的点);
一开始还以为可能出现只有一条链没有环的,但是因为每个点都有一条出边,所以不必担心;
#include<cstdio> #include<cstring> #include<stack> #include<algorithm> using namespace std; const int maxn=1e5+10; int pre[maxn*2],last[maxn],other[maxn*2],l; stack<int> s; void add(int x,int y) { l++; pre[l]=last[x]; last[x]=l; other[l]=y; } int belong[maxn]; int qw; int n; int ru[maxn]; int cnt,dfn[maxn],low[maxn]; int next[maxn]; void dfs(int x) { s.push(x); dfn[x]=low[x]=++cnt; ru[x]=1; for(int p=last[x];p;p=pre[p]) { int v=other[p]; if(!dfn[v]) { dfs(v); low[x]=min(low[x],low[v]); } else if(ru[v]) { low[x]=min(low[x],dfn[v]); } } if(dfn[x]==low[x]) { belong[x]=++qw; while(!s.empty()) { int y=s.top(); s.pop(); ru[y]=0; belong[y]=qw; if(y==x) break; } } } int ring[maxn]; int ans[maxn]; void search(int x,int y,int stp) { if(ans[y]) { ans[x]=ans[y]+stp; return ; } else search(x,next[y],stp+1); } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&next[i]); add(i,next[i]); if(next[i]==i) ans[i]=1; } for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i);//一定要注意图不一定都联通 for(int i=1;i<=n;i++) { ring[belong[i]]++;//记录环的大小 } for(int i=1;i<=n;i++) { if(ring[belong[i]]!=1) ans[i]=ring[belong[i]]; } for(int i=1;i<=n;i++) { if(!ans[i]) search(i,next[i],1); } for(int i=1;i<=n;i++) { printf("%d\n",ans[i]); } return 0; }
标签:缩点,tarjan,万圣节,int,dfn,maxn,low,ans,include 来源: https://www.cnblogs.com/WHFF521/p/11526185.html