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果然还是挂了(悲)

留作警示,日后一定注意函数嵌套时各个量的更新顺序。

posted @ 2022-05-15 21:45  筱星Shea  阅读(143)  评论(1编辑  收藏  举报