题目大意:每个人每一轮可以把消息传给另一个人,问几轮后某个人可以从人
听到自己的消息。
题解:tarjian缩点,求缩点后缩的点包含的最少的点个数。
代码:
正解
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #define maxn 200009 using namespace std; int top,n,sumedge,sumclr,tim,ans; int head[maxn],Stack[maxn],instack[maxn],low[maxn],dfn[maxn],cnt[maxn]; struct Edge{ int x,y,nxt; Edge(int x=0,int y=0,int nxt=0): x(x),y(y),nxt(nxt){} }edge[maxn]; void add(int x,int y){ edge[++sumedge]=Edge(x,y,head[x]); head[x]=sumedge; } void Tarjian(int x){ Stack[++top]=x;instack[x]=true; low[x]=dfn[x]=++tim; for(int i=head[x];i;i=edge[i].nxt){ int v=edge[i].y; if(instack[v])low[x]=min(low[x],dfn[v]); else if(!dfn[v]){ Tarjian(v); low[x]=min(low[x],low[v]); } } if(low[x]==dfn[x]){ ++sumclr; while(Stack[top+1]!=x){ cnt[sumclr]++; instack[Stack[top]]=false; top--; } } } int main(){ scanf("%d",&n);ans=n+1; for(int i=1;i<=n;i++){ int x; scanf("%d",&x); add(i,x); } for(int i=1;i<=n;i++)if(!dfn[i])Tarjian(i); for(int i=1;i<=sumclr;i++)if(cnt[i]!=1)ans=min(ans,cnt[i]); printf("%d ",ans==n+1?0:ans); return 0; }
暴力
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<algorithm> #include<cstdio> #define maxn 200001 using namespace std; int n,ans,tim,m; struct Node{ int fa,tag,v,vis; }g[maxn]; void dfs(int x,int fa){ g[x].tag=++tim;g[x].fa=fa; if(!g[g[x].v].fa)dfs(g[x].v,fa); else if(g[g[x].v].fa==fa) ans=min(ans,tim-g[g[x].v].tag+1); } int main(){ scanf("%d",&n);ans=n+1; for(int i=1;i<=n;i++)scanf("%d",&g[i].v); for(int i=1;i<=n;i++) if(!g[i].fa)dfs(i,i); printf("%d ",ans); return 0; }