• 题解 P6004 【[USACO20JAN]Wormhole Sort S】


    这题真的是非常标准的模板题啊

    看到连最少的边,第一时间会想到 (kruskal) .这道题的难点其实就一个:你要注意到连边权最大的边使整个图联通

    为什么:题意是第i个点想走到 (pos[i]) ,也就是说点i和点 (pos[i]) 必须要联通.

    为什么想不到 (kruskal) :因为 (kruskal) 是最小生成树,比较难想到两条边权大的边连起来并不会影响最小权值.

    扯远了进入正题:

    1.怎么保证连的边的权值最大:

    将边权从大到小排列,需要拿的边尽量拿(因为并不会影响最小权值).

    2.怎么查两点是否连通:

    这个是 (kruskal) 算法最基本的要领.如果一个点的父亲 (fat[i]) 等于另外一个点的父亲 (fat[j]), 那么我们可以确定这两点连通

    3.要连什么点

    细心观察会发现,第i个点走到 (pos[i]) 可以转化为点i和点 (pos[i]) 连通.

    4.怎么判断什么时候全图连通:

    因为要求是一定要全部连通才行,所以如果有一个点不连通,后面怎么连通都没用.而如果有一个点连通了,就算后面再怎么连,最后这个点仍然连通.所以,我们可以做一个指针.指针从1开始,表示第一个不连通的点.每次连边之前先确定还有哪条边不连通.如果我们发现连通的点数已经大于总的点数,那么答案就是输出了

    上代码:(124ms吊打目前所有解法)

    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    inline int read() {
          int x=0,w=1;
          char ch;
          while(ch<'0'||ch>'9')
          {
              if(ch=='-')
                  w=-1;
              ch=getchar();
         }
         while(ch>='0'&&ch<='9')
             x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
         return x*w;
     }
    int n,m,pos[100005],tot = 0,fat[100005], ans = -1;
    struct Edge{
      int from,to,dis;
    }edge[300005];
    int father(int x){
    	while(x!=fat[x]) x=fat[x]=fat[fat[x]];//这个是kruskal的一个加速方法,在查自己的时候可以直接更新父亲
    	return x;
    }
    void Union(int x, int y){
      fat[father(y)] = father(x);
    }
    void add(int f, int t, int d){
      edge[++tot].from = f;
      edge[tot].to = t;
      edge[tot].dis = d;
    }
    //不解释
    bool sorted(Edge a, Edge b){
      return a.dis>b.dis;//从大到小排列
    }
    int main(){
      n = read();m = read();
      for (int i=1;i<=n;i++) pos[i] = read();
      for (int i=0;i<m;i++){
        int a,b,c;
        a = read();b = read(); c = read();
        add(a,b,c);//连边
      }
      sort(edge+1,edge+tot+1,sorted);//从大到小排列
      int ptr = 1;
      for (int i=1;i<=n;i++) fat[i] = i;//自己爸爸一开始就是自己
      for (int i=1;i<=tot;i++){
        while(father(ptr)==father(pos[ptr])) {ptr++; if (ptr>n) goto abcd;}//当我爸跟他爸是同一个人就增加,直到我跟他都不存在或者我爸不是他爸
        if (father(pos[edge[i].from])!=father(pos[edge[i].to])){
          Union(pos[edge[i].from],pos[edge[i].to]);//如果他爸不是我爸,那我将我爸设成他爸
          ans = edge[i].dis;//答案就是现在的边权
        }
      }
      abcd:;
      printf("%d",ans);
    }
    
    
  • 相关阅读:
    【C++程序员学 python】python 的文件类型
    Python如何下载文件
    【C++程序员学 python】python split and join 分割与合并
    知道创宇研发技能表v2.1
    Scapy:局域网MAC地址扫描脚本
    LeetCode: Linked List Cycle II 解题报告
    LeetCode: Insertion Sort List 解题报告
    Lintcode: Minimum Adjustment Cost 解题报告
    LeetCode: Merge Two Sorted Lists 解题报告
    LeetCode: Palindrome Partitioning II 解题报告
  • 原文地址:https://www.cnblogs.com/DannyXu/p/12237529.html
Copyright © 2020-2023  润新知