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