赤裸裸的最小生成树。只是要求输出字典序最小的连接方案。所以在边的排序时要注意了,有可能存在边的权值是相同的边。所以在这种情况下,要按他们的顶点序列排序。直接把STL搬上了,很好很强大。
#include <cstdio> #include <vector> #include <algorithm> #define MAXN 10010 using namespace std; int v[MAXN], u[MAXN], w[MAXN], r[MAXN], par[MAXN]; vector<pair<int, int> > vv; int cmp(const int &i, const int &j) { if(w[i] != w[j]) { return w[i] < w[j]; } else { if(u[i] != u[j]) { return u[i] < u[j]; } else { return v[i] < v[j]; } } } int cmp2(const pair<int, int> &a, const pair<int, int> &b) { if(a.first != b.first) { return a.first < b.first; } else { return a.second < b.second; } } void bin(int i, int j) { par[i] = j; } int find(int x) { return par[x] == x ? x : par[x] = find(par[x]); } bool check(int n) { for(int i = 2; i <= n; i++) { if(find(i) != find(i-1)) { return false; } } return true; } int main(int argc, char* argv[]) { int T, i, j, g, ecnt, ut, vt, t, n, uf,vf; scanf("%d", &T); while(T--) { ecnt = 0; scanf("%d", &n); for(i = 1; i <= n; i++) { par[i] = i; } for(i = 1; i <= n; i++) { for(j = 1; j <= n; j++) { scanf("%d", &g); if(g != 0) { if(i < j) { u[ecnt] = i; v[ecnt] = j; } else { v[ecnt] = i; u[ecnt] = j; } w[ecnt] = g; r[ecnt] = ecnt; ecnt++; } } } if(check(n)) { continue; } sort(r, r+ecnt, cmp); for(i = 0; i < ecnt; i++) { t = r[i]; ut = u[t]; vt = v[t]; uf = find(ut); vf = find(vt); if(uf != vf) { vv.push_back(make_pair(ut, vt)); bin(uf, vf); if(check(n)) { break; } } } if(i == ecnt) { printf("-1/n"); vv.clear(); continue; } sort(vv.begin(), vv.end(), cmp2); printf("%d %d", vv[0].first, vv[0].second); for(i = 1; i < vv.size(); i++) { printf(" %d %d", vv[i].first, vv[i].second); } printf("/n"); vv.clear(); } return 0; }