洛谷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;
}