给出一个n(n<=100)结点的图,求苗条度(最大边减最小边的值)尽量小的生成树。
kruskal算法:
对边权从小到大排序,然后枚举第一条边。根据kruskal的贪心思想,当最小的那条边确定了,那么MST的最大边也就随之确定,且剩余的边中没有比最大边的边权小的边。
菜比的代码总是很繁琐。为了判断所有点是否连通,就用了Union-find set的启发式合并——用一个cnt,记录选了多少次点就行了,煞笔!
而且我因为题目给的是无向图,就建了双向边,又傻逼了,kruskal只是枚举边,然后判断两点是否连通,根本不管你是单向还是双向,这样子浪费了大量的时间在判断上
自己1A的代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#define mes(s,c) memset(s,c,sizeof(s))
#define rep(i,n) for(int i=0;i<(n);++i)
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define FORD(i,a,b) for(int i=(a);i<=(b);++i)
const int maxm=5010;
const int maxn=110;
const int INF=1<<30;
using namespace std;
int n,m;
struct Edge{
int u,v,w;
Edge(int from,int to,int d):u(from),v(to),w(d){}
bool operator<(const Edge&x)const{
return w<x.w;
}
};
vector<Edge> edges;
int f[maxn],rank[maxn],size[maxn];
int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
void union_find(int x,int y)
{
if(x==y) return;
if(rank[x]<rank[y]){
f[x]=y;
size[y]+=size[x];
}else{
f[y]=x;
size[x]+=size[y];
if(rank[x]==rank[y]){
rank[x]++;
}
}
}
void Init()
{
edges.clear();
mes(rank,0);
mes(size,0);
FORD(i,1,n) f[i]=i;
}
int main()
{
while(scanf("%d%d",&n,&m)){
if(n==0&&m==0) break;
Init();
int u,v,w;
rep(i,m){
scanf("%d%d%d",&u,&v,&w);
edges.push_back(Edge(u,v,w));
edges.push_back(Edge(v,u,w));
}
sort(edges.begin(),edges.end());
int ans=INF;
bool flag=true;
for(int i=0;flag&&i<m*2;++i){
int s=edges[i].w;
FORD(i,1,n) f[i]=i;
mes(rank,0);
FORD(i,1,n) size[i]=1;
FOR(j,i,m*2){
int f_u=find(edges[j].u);
int f_v=find(edges[j].v);
if(f_u!=f_v){
union_find(f_u,f_v);
if(size[find(f_u)]==n){
ans=min(edges[j].w-s,ans);
break;
}
}
}
}
if(ans==INF) puts("-1");
else printf("%d\n",ans);
}
return 0;
}
修改过的代码:快了130MS
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#define rep(i,n) for(int i=0;i<(n);++i)
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
using namespace std;
const int maxn=110,maxm=5010,INF=1<<30;
int n,m;
int f[maxn];
struct Edge{
int u,v,w;
Edge(int from,int to,int d):u(from),v(to),w(d){}
bool operator<(const Edge&x)const{
return w<x.w;
}
};
vector<Edge> edges;
int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
void makeSet(){rep(i,n+1)f[i]=i;}
void kruskal(){
sort(edges.begin(),edges.end());
int ans=INF;
rep(i,m){
makeSet();
int cnt=0;
FOR(j,i,m){
int f_u=find(edges[j].u);
int f_v=find(edges[j].v);
if(f_u!=f_v){
f[f_u]=f_v;
cnt++;
if(cnt==n-1){
ans=min(ans,edges[j].w-edges[i].w);
break;
}
}
}
}
if(ans==INF) puts("-1");
else printf("%d\n",ans);
}
int main()
{
while(~scanf("%d%d",&n,&m)){
if(n==0&&m==0) break;
int u,v,w;
edges.clear();
rep(i,m){
scanf("%d%d%d",&u,&v,&w);
edges.push_back(Edge(u,v,w));
}
kruskal();
}
}