Connect them

zoj3204:

最小生成树,要求最小字典序的解。

用kruscal算法,先排序,输出的时候也要排序。

  1 /*
  2 zoj3204 
  3 
  4 
  5 解题思路:
  6 赤裸裸的最小生成树。只是要求输出字典序最小的连接方案。
  7 所以在边的排序时要注意了,有可能存在边的权值是相同的边。
  8 所以在这种情况下,要按他们的顶点序列排序。直接把STL搬上了,很好很强大。 */ 
  9 #include<iostream>
 10 #include<cstdio>
 11 #include<iostream>
 12 #include <stdio.h>
 13 #include <stdlib.h>
 14 #include <cstdio>
 15 #include <cstring>
 16 #include<cmath>
 17 #include<algorithm>
 18 using namespace std;//这句写的时候千万别丢,不然许多函数无法使用 
 19 const int MAX=110; 
 20 struct Node{
 21     int from, to;
 22     int w;
 23     
 24 }edge[MAX*MAX];//记录读取时边的端点和权值 
 25 
 26 Node ans[MAX*MAX];//记录构成最小生成树里面的边 (边端点) 
 27 int n;//点的个数 
 28 int fa[MAX];// 并查集的 
 29 int tol;//记录最小生成树边的个数 
 30 int cnt;//记录ans里的边的个数 
 31  void addedge(int u ,int v,int w){
 32      edge[tol].from=u;
 33      edge[tol].to=v;
 34      edge[tol].w=w;
 35      tol++;
 36      
 37  }//添加边额操作 
 38 void makeset(){
 39     for(int i=1;i<=n;i++){
 40     fa[i]=i;    
 41         
 42     }
 43     
 44 }//并查集的初始化 ,也可以直接初始化为-1 
 45 int Find(int x){
 46     while(x!=fa[x])
 47     x=fa[x];
 48     return x;
 49 }//并查集的查找操作 
 50 void uion(int x,int y){
 51     int a=Find(x);
 52     int b=Find(y);
 53     if(a!=b){
 54         ans[cnt].from=x;
 55         ans[cnt].to=y;
 56         cnt++;
 57         fa[a]=b;
 58         }
 59     
 60     }//并查集的合并操作 
 61 int cmp1(Node a,Node b){
 62     if(a.w!=b.w)return a.w<b.w;
 63     else {if(a.from==b.from)
 64         
 65     
 66           return a.to<b.to;
 67           else
 68           return a.from<b.from;
 69     }
 70 }//比较器首先按w从小到大排序,若w相等,则依次按照from,to进行排序 ,这是给边排序 
 71 int cmp2(Node a,Node b){
 72     
 73     if(a.from!=b.from)return a.from<b.from;
 74     else
 75     return a.to<b.to;
 76 }//这个比较器主要是给ans里面的边排序,使其按照要求输出 
 77 int main(){
 78     int t;
 79     scanf("%d",&t);
 80     while(t--){
 81         scanf("%d",&n);
 82         tol=0;
 83         cnt=0;//一定要在该处初始化tol,cnt否则会报超时的错误 
 84        makeset();
 85        int d;
 86         for(int i=1;i<=n;i++){
 87             
 88             for(int j=1;j<=n;j++){
 89                 scanf("%d",&d);
 90                 if(j<=i)continue;
 91                 if(d==0)continue;//这样读取会使避免重边的影响 
 92                 addedge(i,j,d);//前面的d会被后面的覆盖 
 93                 
 94             }
 95         }
 96         sort(edge,edge+tol,cmp1);//排序 
 97         for(int i=0;i<tol;i++)
 98              uion(edge[i].from,edge[i].to);
 99         
100         sort(ans,ans+cnt,cmp2);
101         if(cnt!=n-1){
102         printf("-1
");
103         continue;}//这一步很重要,是判断能不能形成最小生成树的 
104         else{
105             
106         
107         for(int i=0;i<cnt-1;i++){
108             printf("%d %d ",ans[i].from,ans[i].to);//注意题目给出的输出格式 
109             }
110             printf("%d %d
",ans[cnt-1].from,ans[cnt-1].to);
111             
112     }
113     }
114     
115 }
View Code