zoukankan      html  css  js  c++  java
  • Luogu P2661 信息传递

    传送门

    一眼就能看出来是个并查集 但是并不会写...

    看了一下题解说是并查集求最小环qwq

    所以,每次加入第i个小同学,判断如果他要告诉的小同学k最后会告诉他(也就是转回来了),

    就说明出现了一个环,这时更新一下最小环;

    否则就记一下他要告诉的小同学fa[x](为下一个环做铺垫)

      (如果已经找到环就不记,否则下次有小同学指向这个环的时候就会进入死循环(感谢题解))

    因为每个点的出度都是1,所以当某几个点已经形成了一个环的时候,他们就不可能属于别的环了,

    也就是说每个点只能属于0(入度 = 0)或1个环,

    可以得出当前这个点形成的环一定是它所能形成的最优解(最短的)!

    当发现环的时候,在getfa里面用一个depth记录深度(环的长度);

    至于注意事项...一开始我写的是

    int getfa(int x,int &d) {
        d++;
        if(fa[x] == x)
            return x;
        return fa[x] = getfa(fa[x],d);
    }

    然而wa了,对照题发现最后一句是错的qaq

    于是自己写了一堆测试数据才想明白:

    因为每次判断都要调用一次getfa函数,所以即使没有找到环,经过的小同学的fa[]也是动态变化的,

    这就导致当最后找到环的时候,中间的很多步骤都被跳过了,

    并且由于depth每次清零,所以最后得到的depth并不是真正的答案。

    解决方案:不改变fa[x] 

      return getfa(fa[x],d);

    (其实我感觉把每个点的步数记下来也可以qwq但是没写出来...以后再说吧x)

    完整代码:

    #include<cstdio>
    #define min(x,y) (x)<(y)?(x):(y)
    using namespace std;
    int fa[1000005],n,k,dpth,ans = 10000005;
    int getfa(int x,int &d) {
        d++;
        if(fa[x] == x)
            return x;
        return getfa(fa[x],d);
    }
    int main() {
        scanf("%d",&n);
        for(int i = 1; i <= n; i++)
            fa[i] = i;
        for(int i = 1; i <= n; i++) {
            scanf("%d",&k);
         dpth = 0;
            if(getfa(k,dpth) == i) 
                ans = min(ans,dpth);
            else
                fa[i] = k;
        }
        printf("%d",ans);
        return 0;
    }
    View Code

     

     

     

      

     

  • 相关阅读:
    centos tar压缩与解压缩命令大全
    Nginx编译安装(Centos)
    Nginx的启动脚本(Centos)
    ffmpeg 音频转换(amr2mp3)
    免费国内外"代码托管服务器"收集
    cocos2dx 字符串拼接
    cocos2dx 3.0 中文 iconv 转换函数
    cocos2dx -- 学习笔记
    游戏设计
    梦想经不起等待 -- 美文转载
  • 原文地址:https://www.cnblogs.com/mogeko/p/9966926.html
Copyright © 2011-2022 走看看