洛谷P1547 Out of Hay

题目背景

奶牛爱干草

题目描述

Bessie 计划调查N (2 <= N <= 2,000)个农场的干草情况,它从1号农场出发。农场之间总共有M (1 <= M <= 10,000)条双向道路,所有道路的总长度不超过1,000,000,000。有些农场之间存在着多条道路,所有的农场之间都是连通的。

Bessie希望计算出该图中最小生成树中的最长边的长度。

输入输出格式

输入格式:
两个整数N和M。

接下来M行,每行三个用空格隔开的整数A_i, B_i和L_i,表示A_i和 B_i之间有一条道路长度为L_i。

输出格式:
一个整数,表示最小生成树中的最长边的长度。

输入输出样例

输入样例#1:
3 3
1 2 23
2 3 1000
1 3 43
输出样例#1:
43

【题解】
发现神犇用的都是Kruskal算法,我就给大家另一种思路:Prim算法(求最小生成树的另一种方法)。

首先,这道题是个裸的最小生成树模板题,与模板的唯一差别是:模板求的是最小生成树的各边的长度之和,而这道题求的是最小生成树的边的最大权。

但是,虽然说这道题可以用Prim算法,但它的效率在这里比Kruskal算法差太多了(笔者跑两个算法,前者1266ms,后者16ms),所以我还是建议大家用Kruskal算法,我的程序只代表另一种思路。

Kruskal算法以边为核心搜最小生成树,Prime算法以点为核心搜最小生成树,所以在点少时用Prim算法,点多时用Kruskal算法。

不过,一般来说,Kruskal算法时间复杂度为O(nlongn),Prim算法时间复杂度为
【邻接矩阵:O(v) 邻接表:O(elog2v)】,所以,打Kruskal大部分情况下是比较快的。

模板程序改一句话即可A此题(既然是模板就不用解释了吧):

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define fp(i,a,b) for(i=a;i<=b;i++)
#define fq(i,a,b) for(i=a;i>=b;i--)
#define il inline
#define re register
#define ll long long 
using namespace std;
int map[5005][5005]={},dis[100005]={};
bool vis[100005]={};
il int gi()//读入优化
{
  re int x=0;
  re short int t=1;
  re char ch=getchar();
  while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
  if(ch=='-') t=-1,ch=getchar();
  while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  return x*t;
}
int main()
{
  re int i,j,k,n,m,x,y,z,ans=0;
  memset(map,0x3f3f3f,sizeof(map));//这是给数组赋极大值的好方法
  n=gi();m=gi();
  fp(i,1,m)
  {
    x=gi();y=gi();z=gi();
    if(z<map[x][y]) map[x][y]=z,map[y][x]=z;
  }
  memset(dis,0x3f3f3f,sizeof(dis));
  fp(i,1,n) vis[i]=1;
  dis[1]=0;
  fp(i,1,n)
  {
    k=0;
    fp(j,1,n) if(vis[j]==1&&(dis[j]<dis[k])) k=j;
    vis[k]=0;
    fp(j,1,n) if(vis[j]==1&&(map[k][j]<dis[j])) dis[j]=map[k][j];
  }
  fp(i,1,n) ans=max(ans,dis[i]);//把求各边长度之和改为求边的最大长度
  printf("%d\n",ans);
  return 0;
}

当然,更快的方法也要记录下来(Kruskal):

#include<iostream>
#include<cstdio>
#include<algorithm>
 using namespace std;
struct tt
{
    int from,to,cost;
}a[10005];
int father[2005];
int k,n;
int  find(int x)
{
    if (father[x]==0) return x;
    return find(father[x]);
}
bool comp(tt a,tt b)
{
    return a.cost<b.cost;
}
int main()
{
    cin>>n>>k;
    for (int i=1;i<=k;i++)
        scanf("%d%d%d",&a[i].from,&a[i].to,&a[i].cost);
    sort(a+1,a+k+1,comp);
    int i=1,re=1;
    while(i<n)
    {
        int p=find(a[re].from);
        int q=find(a[re].to);
        if (p!=q)
        {
            i++;
            father[p]=q;
        }
        re++;
    }
    cout<<a[re-1].cost<<endl;
    return 0;
}
posted @ 2017-08-09 22:31  小蒟蒻ysn  阅读(137)  评论(0编辑  收藏  举报