P2661 資訊傳遞(tarjan判最小環/拓撲思想+dfs)
阿新 • • 發佈:2018-12-10
題解:可以看出這個題是一個求圖的最小環的板題
一:先找出入度為0的點,把這些點以及這些出邊刪去,最後剩餘的跑出最小環
附上程式碼:
#include<bits/stdc++.h> using namespace std; const int maxn=2e5+50; int in[maxn],book[maxn],mapp[maxn],ans,temp; void dfs(int beginn) { book[beginn]=1; in[mapp[beginn]]--; if(in[mapp[beginn]]==0){ dfs(mapp[beginn]); } } void dfs1(int anc,int beginn) { book[beginn]=1; temp++; if(mapp[beginn]==anc){ return ; }else{ dfs1(anc,mapp[beginn]); } } int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&mapp[i]); in[mapp[i]]++; } for(int i=1;i<=n;i++){ if(in[i]==0&&!book[i]){ dfs(i); } } ans=0x3f3f3f3f; for(int i=1;i<=n;i++){ if(in[i]&&!book[i]){ temp=0; dfs1(i,i); ans=min(ans,temp); } } printf("%d\n",ans); return 0; }
二:使用tarjan直接更新出最小環(最小環至少長度為2)即可
附上程式碼:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn=2e5+50; struct edge{ int v,next; }; edge edges[maxn]; int head[maxn],cnt; int dfn[maxn],low[maxn],stack[maxn],visit[maxn],tot,iindex; int ans=0x3f3f3f3f,temp; int n,v; void add(int x,int y) { edges[cnt].v=y; edges[cnt].next=head[x]; head[x]=cnt++; } void tarjan(int x) { dfn[x]=low[x]=++tot; stack[++iindex]=x; visit[x]=1; for(int i=head[x];~i;i=edges[i].next){ if(!dfn[edges[i].v]){ tarjan(edges[i].v); low[x]=min(low[x],low[edges[i].v]); }else if(visit[edges[i].v]){ low[x]=min(low[x],dfn[edges[i].v]); } } temp=0; if(low[x]==dfn[x]){ do{ temp++; visit[stack[iindex]]=0; iindex--; }while(x!=stack[iindex+1]); if(temp>1){ ans=min(ans,temp); } } } int main() { memset(head,-1,sizeof(head)); scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&v); add(i,v); } tot=0,iindex=0; for(int i=1;i<=n;i++){ if(!dfn[i]){ tarjan(i); } } printf("%d\n",ans); return 0; }