#include<iostream> #include<vector> #include<algorithm> using namespace std; const int N = 110; int p[N];//保存所有结点的状态 struct edge { int u, v, w, state; edge(int u, int v, int w, int state) { this->u = u, this->v = v, this->w = w, this->state = state; } edge() { } bool operator < (const edge&m) const{ return this->w < m.w; } }; int find(int x) { if (p[x] != x)p[x] = find(p[x]); return p[x]; } int main() { int n; while (cin >> n) { if(n==0)break; vector<edge> E; int count = 0;//已经选的边的数量,有些边已经存在,考虑在此情况下怎么才能成本最低 //初始化并查集 for (int i = 1; i <= n; i++) { p[i] = i; } for (int i = 1; i <= n * (n - 1) / 2; i++) { int u, v, w, state; cin >> u >> v >> w >> state; if(!state) E.push_back(edge(u, v, w, state));//未修建的话要放入动态数组中,接下来选 else { //已经存在的路要加入并查集 int root1 = find(u); int root2 = find(v); if (root1 != root2)p[root1] = root2; count++; } } sort(E.begin(), E.end()); int cost = 0; //因为我用的是动态数组,插入是从0位置开始插入的 for (int i = 0; i < E.size();i++) { int u = E[i].u, v = E[i].v, w = E[i].w; if (find(u) != find(v)) { //当两个点不在一个集合时,要选这条边 int root1 = find(u); int root2 = find(v); p[root1] = root2; cost += w; count++; } if (count == n - 1)break;//已经找到生成树的话可以提前退出 } cout << cost << endl; } return 0; } //啊啊啊Kruskal算法好好用