码迷,mamicode.com
首页 > 其他好文 > 详细

题解 P6004 【[USACO20JAN]Wormhole Sort S】

时间:2020-01-28 12:21:13      阅读:57      评论:0      收藏:0      [点我收藏+]

标签:add   for   进入   mes   比较   struct   std   space   题解   

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

看到连最少的边,第一时间会想到 $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】

标签:add   for   进入   mes   比较   struct   std   space   题解   

原文地址:https://www.cnblogs.com/DannyXu/p/12237529.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!