题解 P6004 [USACO20JAN]Wormhole Sort S

Posted dannyxu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解 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);
}

以上是关于题解 P6004 [USACO20JAN]Wormhole Sort S的主要内容,如果未能解决你的问题,请参考以下文章

题解 P3605 [USACO17JAN]Promotion Counting晋升者计数

USACO08JAN Telephone Lines 题解

[USACO09JAN]Earthquake Damage

题解晋升者计数 Promotion Counting [USACO 17 JAN] [P3605]

洛谷 P2879 [USACO07JAN]区间统计Tallest Cow 题解

题解[USACO17JAN]Balanced Photo G