题解 P2661 【信息传递】

anyway

2017-10-27 16:24:29

Solution

**并查集求最小环** 把每个同学看成一个点,信息的传递就是在他们之间连有向边,游戏轮数就是求最小环。 图论求最小环,我在里面看到了并查集。 假如说信息由A传递给B,那么就连一条由A指向B的边,同时更新A的父节点,A到它的父节点的路径长也就是B到它的父节点的路径长+1。 这样我们就建立好了一个图,之后信息传递的所有环节都按照这些路径。游戏结束的轮数,也就是这个图里最小环的长度。 如果有两个点祖先节点相同,那么就可以构成一个环,长度为两个点到祖先节点长度之和+1。 和下面的并查集有点不一样的。 (合作&思路基础: bie淖\_kkk ) ```cpp #include<cstdio> #include<iostream> using namespace std; int f[200002],d[200002],n,minn,last; //f保存祖先节点,d保存到其祖先节点的路径长。 int fa(int x) { if (f[x]!=x) //查找时沿途更新祖先节点和路径长。 { int last=f[x]; //记录父节点(会在递归中被更新)。 f[x]=fa(f[x]); //更新祖先节点。 d[x]+=d[last]; //更新路径长(原来连在父节点上)。 } return f[x]; } void check(int a,int b) { int x=fa(a),y=fa(b); //查找祖先节点。 if (x!=y) {f[x]=y; d[a]=d[b]+1;} //若不相连,则连接两点,更新父节点和路径长。 else minn=min(minn,d[a]+d[b]+1); //若已连接,则更新最小环长度。 return; } int main() { int i,t; scanf("%d",&n); for (i=1;i<=n;i++) f[i]=i; //祖先节点初始化为自己,路径长为0。 minn=0x7777777; for (i=1;i<=n;i++) { scanf("%d",&t); check(i,t); //检查当前两点是否已有边相连接。 } printf("%d",minn); return 0; } ```