NOIP2013 提高组 day2 第三题 

 

Kruskal算法是图论里求最小生成树的高效算法

借用并查集来巧妙的算最小生成树

思路是这样的:

先把所有的边排序,然后根据需要来依次合并权值最大(小)边的端点(或是计算路线中所有边中的最小值的最大值)

注 但是Kruskal并不能全过,只过得到60%,还有405要使用树上路径倍增,但暂时还没有掌握

题意就是只要有路把它们连起来,让这些路中的承重的最小值最大就可以了,可以使用Kruskal

注意并查集中的几个函数,很简单的,不要记错了

代码

 

#include<cstdio>
#include<iostream>//并查集 Kruskal
#include<algorithm>
using namespace std;
const int maxx=50005;
int fat[10001];
int n,q,tot,m;
struct xx{
int x,y,w;
}bian[maxx];
int father(int x)//寻找父亲
{
  if(fat[x]!=x) fat[x]=father(fat[x]);
  return fat[x];
}
void unionn(int a,int b)//注意并查集是把父亲相连
{
  int fa=father(a);
  int fb=father(b);
  if(fa!=fb) fat[fa]=fb;
}
bool cmp(const xx a,const xx b)
{
return b.w<a.w;
}
int main()
{
  freopen("truck.in","r",stdin);
  freopen("truck.out","w",stdout);
  cin>>n>>m;
  for(int i=1;i<=m;i++)
  {
    int x,y,z;
    scanf("%d %d %d",&x,&y,&z);
    bian[i].x=x,bian[i].y=y,bian[i].w=z;
  }
  sort(bian+1,bian+m+1,cmp);
  cin>>q;
  for(int i=1;i<=q;i++)
  {int x,y,minn=1e6,k=1;
    for(int i=1;i<=n;i++)fat[i]=i;//初始化
    scanf("%d %d",&x,&y);
    for(int i=1;i<=m;i++)
    {
      if(father(x)==father(y)){
      printf("%d\n",minn);
      break;
    }
    else if(father(bian[i].x)!=father(bian[i].y))
    {
      unionn(bian[i].x,bian[i].y);
      //if(bian[i].w<minn)//这步其实没必要
      minn=bian[i].w;
    }
    }
  if(father(x)!=father(y))printf("-1\n");
  }
  return 0;
}

 

posted on 2016-07-12 21:56  李万  阅读(166)  评论(0编辑  收藏  举报