pku 3522 Slim Span
题意很简单,就是找出一棵最大边值与最小边值差值最小的生成树,首先,从i=0开始枚举以当前边为最小用kruskal 算法求最小生成树,找出最小的差值
本来是1A的,不过那个时间500+ms 实在太难接受了,所以一直在剪枝,中间WA了几次,最后,嘻嘻,如愿以偿了,47ms,主要是减少不必要的循环
排完序之后,自然是开始枚举生成树的起始边
1)若以当前的起始边e[i]用kruskal算法求出的生成树是非联通的,则不用枚举了,因为之后也没法形成联通的生成树了
2)在kruskal算法过程中,若出现边值与起始边值的差值大于已求得的最小差值ans,则也可以退出循环了,但还是要继续枚举起始边,退出的是kruskal算法,因为之后还是有可能出现更小的差值的
ps:就是在这里多WA了几次
#include<iostream>
#include<string>
#include<algorithm>
#define MAXN 1001*500
using namespace std;
int f[101],n,m,ans;
struct edge
{
int u,v,w;
}e[MAXN];
inline void init()
{
for(int i=0;i<=n;i++)
f[i]=i;
}
inline int find(int x)
{
while(x!=f[x])
{
f[x]=f[f[x]];
x=f[x];
}
return f[x];
}
inline int Union (int i)
{
int a=find(e[i].u);
int b=find(e[i].v);
if(a==b) return 0;
f[b]=a;
return e[i].w;
}
bool cmp(edge a,edge b){
return a.w<b.w;
}
inline int kruskal(int s)
{
int p,max1=0;
init();
int num=0;
for(int i=s;i<m;i++)
{
p=Union(i);
if(p)
{
max1=p;
num++;
if(num>=n-1) break;
}
if(e[i].w-e[s].w>ans&&ans!=-1) return 0;
}
for(int i=2;i<=n;i++)
if(find(i)!=find(i-1))
return -1;
return max1;
}
int main()
{
while(scanf("%d %d",&n,&m)==2&&(n||m))
{
for(int i=0;i<m;i++)
scanf("%d %d %d",&e[i].u,&e[i].v,&e[i].w);
sort(e,e+m,cmp);
ans=-1;
for(int i=0;i<=m-n+1;i++)
{
int tmp=kruskal(i);
if(tmp>0)
{
tmp=tmp-e[i].w;
if(ans>tmp||ans==-1)
ans=tmp;
}
if(tmp==-1) break;//当前以i条边形成的 树不连通
}
printf("%d\n",ans);
}
return 0;
}

浙公网安备 33010602011771号