#include <bits/stdc++.h> using namespace std; #define MAX 200 #define INF 0x7fffffff //无向图,规定两点间只有一条边 //下标从1开始 int graph[MAX+1][MAX+1],points[MAX+1],numbian,numdian,circle[MAX+1]; struct mydata { int from,to,cost; mydata(int from,int to,int cost){ this->from=from; this->to=to; this->cost=cost; } mydata(){} bool operator<(const mydata &a){ return this->cost<a.cost; } }; void prim(){ //加点法 mydata data[MAX+1]; int ok[MAX+1]; memset(ok,0,sizeof(ok)); for(int i=1;i<=numdian;i++){ data[i].from=i; data[i].to=1; data[i].cost=graph[i][1]; } //从点1开始 ok[1]=1; for(int i=0;i<numdian-1;i++){ int min=-1; for(int j=2;j<=numdian;j++){ //注意这里 if(!ok[j]&&(min==-1||data[j].cost<data[min].cost)) min=j; } for(int j=2;j<=numdian;j++){ //其他所有没加进去的点和这个点的距离 if(!ok[j]&&graph[min][j]!=-1&&graph[min][j]<data[j].cost){ data[j].cost=graph[min][j]; data[j].to=min; } } ok[min]=1; cout<<data[min].from<<" -> "<<data[min].to<<endl; } //结果即在data中,有n-1条边 } //适合稀疏的图 void kruskal(){ //加边法 int circle[MAX+1],k=1;//区分连通分量 mydata data[MAX+1]; for(int i=1;i<=numdian;i++) circle[i]=i; for(int i=1;i<=numdian;i++){ for(int j=i;j<=numdian;j++){ if(graph[i][j]!=INF){ data[k].cost=graph[i][j]; data[k].from=i; data[k].to=j; k++; } } } sort(data+1,data+numbian+1); //注意左闭右开区间形式 for(int i=1;i<=numbian;i++){ if(circle[data[i].from]!=circle[data[i].to]){ cout<<data[i].from<<" -> "<<data[i].to<<endl; //更新circle int p=circle[data[i].to]; for(int j=1;j<=numdian;j++){ //反例!!,这样写不可以,因为circle[data[i].to]的值动态变化,不能比较 //目的:把所有是to的分量改为from的,但是to本身也会变呀,导致后续比较都错误 // if(circle[j]==circle[data[i].to]) // circle[j]=circle[data[i].from]; if(circle[j]==p) circle[j]=circle[data[i].from]; } } } } //kruskal更新一次,查找多次的版本 //并查集 // int func(int x){ // //这是一个技巧,因为连通分量数组circle初始化为 // //1 2 ... n,即为每个点的编号,那么对于circle[i]有 // //(1)circle[i]==i,代表他就没变过,所以连通分量编号就是i // //(2)circle[i]!=i,代表被合并了,i合并到了circle[i]里,在返回(1)看看; // //返回值是对应的circle[i]==i的点,修改的也是这个点; // //并且修改所有的circle[x] != x的点; // return circle[x] == x ? x : circle[x] = func(circle[x]); // } // //改成循环 // int func1(int x){ // if(circle[x] == x) return x; // int k=x; // int *changes=new int[numdian],index=0; // while (circle[k] != k) // { // changes[index++]=k; // k=circle[k]; // } // for(int i=0;i<index;i++) circle[changes[i]]=k; // delete[] changes; // return circle[k]; // } // bool find(int x,int y){ // //找是否在同一个连通分量 // //circle按照点的顺序创建 // return func(x)==func(y); // } // void kruskal(){ // //加边法 // int k=1;//区分连通分量 // mydata data[MAX+1]; // for(int i=1;i<=numdian;i++) circle[i]=i; // for(int i=1;i<=numdian;i++){ // for(int j=i;j<=numdian;j++){ // if(graph[i][j]!=INF){ // data[k].cost=graph[i][j]; // data[k].from=i; // data[k].to=j; // k++; // } // } // } // sort(data+1,data+numbian+1); // //注意左闭右开区间形式 // for(int i=1;i<=numbian;i++){ // if(!find(data[i].from,data[i].to)){ // cout<<data[i].from<<" -> "<<data[i].to<<endl; // circle[data[i].to]=circle[data[i].from] // } // } // } int main(){ cin>>numdian>>numbian; for(int i=1;i<=numdian;i++) for(int j=1;j<=numdian;j++) graph[i][j]=INF; for(int i=1;i<=numdian;i++) points[i]=i; for(int i=0;i<numbian;i++){ int x,y,z; cin>>x>>y>>z; graph[x][y]=graph[y][x]=z; } for(int i=1;i<=numdian;i++){ for(int j=1;j<=numdian;j++) cout<<graph[i][j]<<" "; cout<<endl; } // prim(); kruskal(); return 0; }