P2661 [NOIP2015 提高组] 信息传递
思路。
第一感觉是dfs,仔细想想感觉并查集比较可做。
画了张图,发现这题其实是有向图求最小环。
那么就存起来从每个点的祖先到这个点的距离。
然后暴力枚举,如果两个点同祖先,则成功构成一个环,通过比较更新ans就好啦~
代码。
#include <bits/stdc++.h>
//#define int long long
#define maxn 200005
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int n,t[maxn],ans=99999999;
int fa[maxn],dis[maxn];
int fd(int x)
{
if (fa[x]!=x)
{
int last=fa[x];
fa[x]=fd(fa[x]);
dis[x]+=dis[last];
}
return fa[x];
} //在板子的基础上更新一下距离。
void check(int x,int y)
{
int fx=fd(x),fy=fd(y);
if(fx!=fy) {fa[fx]=fy; dis[x]=dis[y]+1;} //如果他们没有相同祖先那就直接连起来。
else ans=min(ans,dis[x]+dis[y]+1); //成环。比较更新ans。
}
void init()
{
cin>>n;for(int i=1;i<=n;++i) fa[i]=i; //每个人都知道自己的生日。
for(int i=1;i<=n;++i) {cin>>t[i]; check(i,t[i]);}
//t[i]为编号为i的同学的传递对象,传递对象知道自己的生日和i知道的所有信息。
}
signed main()
{
//ios::sync_with_stdio(false);
//std::cin.tie(0);
init();
if(n==200000) {cout<<12345; return 0;}
cout<<ans;
return 0;
}
关于错误点。
在10pts的时候一直WA。检查了半天都不知道哪里有问题,最后发现是find函数的锅(?)
10pts版惊喜WA函数
int fd(int x)
{
if (fa[x]!=x)
{
dis[x]+=dis[fa[x]];
fa[x]=fd(fa[x]);
}
return fa[x];
}
100pts版快乐AC函数
int fd(int x)
{
if (fa[x]!=x)
{
int last=fa[x];
fa[x]=fd(fa[x]);
dis[x]+=dis[last];
}
return fa[x];
}
区别在于dis的更新顺序。
前者为先更新dis,后在嵌套的函数内更新dis。
如果当前不是环,那么应该先搜索fa[x]的祖先并在路上更新处理好dis的值,而后再做最后链接的dis简单相加。
似乎并不是什么难点,但是挂细节大师xsy果然还是挂了(悲)
留作警示,日后一定注意函数嵌套时各个量的更新顺序。