ZOJ 3204 Connect them
最小生成树。
做克鲁斯卡尔的时候,边排序的第一关键字是权值,然后是$u$,然后是$v$。记录下用了哪几条边。
因为这些边的第一关键字是权值,所以需要重新按字典序排序。
#pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<ctime> #include<iostream> using namespace std; typedef long long LL; const double pi=acos(-1.0); void File() { freopen("D:\\in.txt","r",stdin); freopen("D:\\out.txt","w",stdout); } template <class T> inline void read(T &x) { char c = getchar(); x = 0; while(!isdigit(c)) c = getchar(); while(isdigit(c)) { x = x * 10 + c - '0'; c = getchar(); } } int T,n,sz,cnt; int c[200][200],f[200],g[40000]; struct Edge { int u,v,c; }e[40000]; int Find(int x) { if(x!=f[x]) return f[x]=Find(f[x]); return f[x]; } bool cmp(Edge a,Edge b) { if(a.c!=b.c) return a.c<b.c; if(a.u!=b.u) return a.u<b.u; return a.v<b.v; } bool cmp2(int a,int b) { if(e[a].u!=e[b].u) return e[a].u<e[b].u; return e[a].v<e[b].v; } int main() { scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&c[i][j]); sz=0; for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { if(c[i][j]==0) continue; e[sz].u=i; e[sz].v=j; e[sz].c=c[i][j]; sz++; } } sort(e,e+sz,cmp); for(int i=1;i<=n;i++) f[i]=i; cnt=n; memset(g,0,sizeof g); for(int i=0;i<sz;i++) { int A=Find(e[i].u), B=Find(e[i].v); if(A==B) continue; f[A]=B; cnt--; g[i]=1; } if(cnt!=1) { printf("-1\n"); continue; } int d=0,tmp[200]; for(int i=0;i<sz;i++) { if(g[i]==1) tmp[d++]=i; } sort(tmp,tmp+d,cmp2); for(int i=0;i<d;i++) { printf("%d %d",e[tmp[i]].u,e[tmp[i]].v); if(i<d-1) printf(" "); else printf("\n"); } } return 0; }