最小生成树【Kruskal】POJ2377,POJ1258,poj2358,hdu1233

来源:互联网 发布:java线程wait notify 编辑:程序博客网 时间:2024/05/29 03:17

最小生成树水题……全部用kruskal模板编写。(结合并查集)


POJ2377

注意kruskal的各个步骤

注意使用时对模板的修改



/*kruskal**并查集实现 **1.边权值排序sort **2.选择最小的边**3.判断最小边上的点是否同一集合  **不是同一集合就合并 */#include <cstdio>#include <vector>#include <algorithm>using namespace std;#define MAX 1002struct edge{int u,v,cost;};vector<edge> G;int V,E;int rank[MAX],par[MAX]; void init(int n){for(int i=0;i<n;i++){rank[i]=0;par[i]=i;}return ;} int find(int x){if(par[x]==x) return x;else return par[x]=find(par[x]);}bool same(int x,int y){return find(x)==find(y);}void unit(int x,int y){x=find(x);y=find(y);if(x==y) return;if(rank[x]<rank[y]){par[x]=y;}else{par[y]=x;if(rank[x]==rank[y]) rank[x]++;}}bool mycom(const edge &e1,const edge &e2){return e1.cost>e2.cost;}int main(){scanf("%d%d",&V,&E);init(V);edge ed;for(int i=0;i<E;i++){scanf("%d %d %d",&ed.u,&ed.v,&ed.cost);G.push_back(ed);}sort(G.begin(),G.end(),mycom);int res=0;int temp=1;for(int i=0;i<E;i++){if(!same( G[i].u, G[i].v ) ){unit(G[i].u,G[i].v);res+=G[i].cost;temp++;}}if(temp!=V){puts("-1");}elseprintf("%d\n",res);return 0;}




POJ1258

处理输入格式,由于是无向图,只需要获得上三角或者下三角的数据即可

然后存进来,用kruskal

不过这道题边比较多,感觉更适合用prim,但是kruskal也能做的嘛~

他俩时间复杂度都是o(E logV)


/*kruskal**并查集实现 **1.边权值排序sort **2.选择最小的边**3.判断最小边上的点是否同一集合  **不是同一集合就合并 */#include <cstdio>#include <vector>#include <algorithm>using namespace std;#define MAX 110struct edge{int u,v,cost;}G[5000];edge ed;int V,E;int rank[MAX],par[MAX]; void init(int n){for(int i=0;i<n;i++){rank[i]=0;par[i]=i;}return ;} int find(int x){if(par[x]==x) return x;else return par[x]=find(par[x]);}bool same(int x,int y){return find(x)==find(y);}void unit(int x,int y){x=find(x);y=find(y);if(x==y) return;if(rank[x]<rank[y]){par[x]=y;}else{par[y]=x;if(rank[x]==rank[y]) rank[x]++;}}bool mycom(const edge &e1,const edge &e2){return e1.cost<e2.cost;}int main(){int n;while(scanf("%d",&n)!=EOF){int t,k=0;for(int i=0;i<n;i++){afor(int j=0;j<n;j++){scanf("%d",&t);if(i<j){ed.u=i,ed.v=j,ed.cost=t;G[k++]=ed;}}} init(n);sort(G,G+k,mycom);int res=0;for(int i=0;i<k;i++){if(!same( G[i].u, G[i].v ) ){unit(G[i].u,G[i].v);res+=G[i].cost;}}printf("%d\n",res);}return 0;}



poj2358

根据题意实际上就是求最小生成树中的最长边。

kruskal是先排序然后依次加入边,(前提是这个边不会构成环),所以每次都是保存最小生成树中最后加入的边

所以最后插入的边就是答案。

#include <cstdio>#include <vector>#include <algorithm>using namespace std;#define MAX 2002struct edge{int u,v,cost;};vector<edge> G;int V,E;int rank[MAX],par[MAX]; void init(int n){for(int i=0;i<n;i++){rank[i]=0;par[i]=i;}return ;} int find(int x){if(par[x]==x) return x;else return par[x]=find(par[x]);}bool same(int x,int y){return find(x)==find(y);}void unit(int x,int y){x=find(x);y=find(y);if(x==y) return;if(rank[x]<rank[y]){par[x]=y;}else{par[y]=x;if(rank[x]==rank[y]) rank[x]++;}}bool mycom(const edge &e1,const edge &e2){return e1.cost<e2.cost;}int main(){scanf("%d%d",&V,&E);init(V);edge ed;for(int i=0;i<E;i++){scanf("%d %d %d",&ed.u,&ed.v,&ed.cost);G.push_back(ed);}sort(G.begin(),G.end(),mycom);int res=G[0].cost;int temp=1;for(int i=0;i<E;i++){if(!same( G[i].u, G[i].v ) ){unit(G[i].u,G[i].v);res=G[i].cost;}}printf("%d\n",res);return 0;}






hdu1233

畅通工程

#include <cstdio>#include <vector>#include <algorithm>using namespace std; #define MAX 102struct edge{int u,v,cost;};vector<edge> G;int ran[MAX],par[MAX];int V,E;/*并查集*/void init(int n){for(int i=0;i<=n;i++){ran[i]=0;par[i]=i;}} int find(int x){if(x==par[x]) return  x;else return par[x]=find(par[x]);}bool same(int x,int y){return find(x)==find(y);}  void unit(int x,int y){x=find(x),y=find(y);if(x==y) return ;if(ran[x]<ran[y]){par[x]=y;}else{par[y]=x;if(ran[x]==ran[y]) ran[x]++;}} bool mycom(const edge &e1,const edge &e2){return e1.cost<e2.cost;}int main(){edge ed;while(scanf("%d",&V)!=EOF&&V!=0){G.clear();E=V*(V-1)/2;for(int i=0; i<E; i++){scanf("%d%d%d",&ed.u,&ed.v,&ed.cost);G.push_back(ed);}sort(G.begin(),G.end(),mycom);init(V);int res=0;for(int i=0;i<G.size();i++){if(!same(G[i].u,G[i].v)){unit(G[i].u,G[i].v);res+=G[i].cost;} }printf("%d\n",res);}return 0;} 







0 0