测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( < 100 );随后的N(N-1)/2行对应村庄间的距离,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间的距离。为简单起见,村庄从1到N编号。 当N为0时,输入结束,该用例不被处理。
对每个测试用例,在1行里输出最小的公路总长度。
3 1 2 1 1 3 2 2 3 4 4 1 2 1 1 3 4 1 4 1 2 3 3 2 4 2 3 4 5 0
3 5
#include <stdio.h>
#include <algorithm>
#define N 101
using namespace std;
int parent[N];
struct Edge{
    int a;
    int b;
    int d;
}E[N*N];
bool cmp(Edge a, Edge b)
{
    return a.d<b.d;
}
int FindRoot(int x)
{
    if(parent[x]==-1) return x;
    else
    {
        int ret=FindRoot(parent[x]);
        parent[x]=ret;
        return ret;
    }
}
int main()
{
    int n;
    while(scanf("%d", &n)!=EOF)
    {
        if(n<=0) break;
        for(int i=1; i<=n*(n-1)/2; i++)
        {
            scanf("%d%d%d", &E[i].a, &E[i].b, &E[i].d);
        }
        for(int i=1; i<=n; i++) parent[i]=-1;
        int treeNum=n;
        int totalDist=0;
        sort(E+1, E+1+n*(n-1)/2, cmp);
        for(int i=1; i<=n*(n-1)/2; i++)
        {
            if(treeNum==1) break;//通了以后就收工
            int x, y;
            x=FindRoot(E[i].a);
            y=FindRoot(E[i].b);
            if(x!=y)
            {
                parent[x]=y;
                treeNum--;
                totalDist+=E[i].d;
            }
        }
        printf("%d\n", totalDist);
    }
    return 0;
} #include <stdio.h>
#include <algorithm>
using namespace std;
struct E{
    int a;
    int b;
    int value;
}edge[5000];
bool cmp(E a,E b){
    return a.value<b.value;
}
int point[5000];
int findroot(int x){
    if(point[x]==-1) return x;
    else{
        int tmp=findroot(point[x]);
        point[x]=tmp;
        return tmp;
    }
}
int main(){
    int n;
    while(scanf("%d",&n)!=EOF){
        int m=(n*(n-1))/2;
        for(int i=1;i<=n;i++){
            point[i]=-1;
        }
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&edge[i].a,&edge[i].b,&edge[i].value);
        }
        sort(edge+1,edge+m+1,cmp);
        int sum=0;
        for(int i=1;i<=m;i++){
            int x=findroot(edge[i].a);
            int y=findroot(edge[i].b);
            if(x!=y){
                sum+=edge[i].value;
                if(x>y) point[x]=y;
                else point[y]=x;
            }
        }
        printf("%d\n",sum);
    }
    return 0;
}
 #include <stdio.h>
typedef struct Edge{
    int from,to,len;
}Edge;
Edge e[10000];
int dad[100],h[100];
void Initial(int n)
{
    for(int i=0;i<=n;i++)
    {
        dad[i]=i;
        h[i]=0;
    }    
}
int Find(int x)
{
    if(x!=dad[x])
        dad[x]=Find(dad[x]);
    return dad[x];
}
void Union(int x,int y)
{
    x = Find(x);
    y = Find(y);
    if(x!=y)
    {
        if(h[x]<h[y])    dad[x]=y;
        else if(h[x]>h[y])    dad[y]=x;
        else{
            dad[y]=x;
            h[x]++;
        }
    }
    return;
}
int cmp(const void *a,const void *b)
{
    return (*(Edge*)a).len-(*(Edge*)b).len;
}
int Kruskal(int n,int num)
{
    Initial(n);
    qsort(e,num,sizeof(e[0]),cmp);
    int sum = 0;
    for(int i=0;i<num;i++)
    {
        if(Find(e[i].from)!=Find(e[i].to))
        {
            Union(e[i].from, e[i].to);
            sum+=e[i].len;
        }
    }
    return sum;
}
int main()
{
    int n,m,ans,i;
    while(scanf("%d",&n)!=EOF)
    {
        if(n==0) break;
        m=n*(n-1)/2;
        for(i=0;i<m;i++)
        {
            scanf("%d %d %d",&e[i].from,&e[i].to,&e[i].len);
        }
        ans=Kruskal(n, m);
        printf("%d\n",ans);
    }
    return 0;
} #include <iostream>
#include <algorithm>
using namespace std;
typedef struct _Edge
{
	int a, b, cost;
	bool operator<(const struct _Edge &e) const { return cost < e.cost;	}
}Edge;
int tree[100] = {-1};
int findroot(int x)
{
	if (-1 == tree[x]) return x;
	tree[x] = findroot(tree[x]);
	return tree[x];
}
int main()
{
	int n = 0;
	while (cin >> n && 0 != n)
	{
		int m = n * (n - 1) / 2, min_cost = 0; Edge eg[5000]; for (int i = 0; i <= n; ++i) tree[i] = -1;
		for (int i = 0; i < m; ++i) cin >> eg[i].a >> eg[i].b >> eg[i].cost; sort(eg, eg + m);
		for (int i = 0; i < m; ++i)
		{
			int a = findroot(eg[i].a), b = findroot(eg[i].b);
			if (a != b) { tree[b] = a; min_cost += eg[i].cost;}
		}
		cout << min_cost << endl;
	}
	return 0;
} #最小生成树Python写法,Kruskal算法
#(把所有点集放在一颗树上就相当于全部点连通;从最小权值构建树开始)
def findRoot(x):         #找树根,如果起始树根为自己
    global tree
    if (tree[x] == -1):
        return x
    else:
        temp = findRoot(tree[x])    
        tree[x] = temp
        return temp
try:
    while True:
        num = int(input())
        if num == 0:
            break
        roadsList = []
        for i in range(num * (num - 1) // 2):
            roadsList.append(list(map(int, input().split())))
        roadsList.sort(key=lambda x: x[2])   #Python中list排序可以指定第几号元素排
        tree = [-1 for i in range(num + 1)]  #初始化树,起始树根都为自己
        result = 0
        for i in range(num * (num - 1) // 2): #循环每条路
            a = findRoot(roadsList[i][0])    #查找路的两端的树根
            b = findRoot(roadsList[i][1])
            if a!=b:                         #如果树根相等说明在同一颗树上
                result += roadsList[i][2]    #因为从最小权值开始,所以得到的是最小生成树
                tree[a] = b          
        print(result)
except Exception:
    pass #include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
struct edge{
    int a,b,cost;
}road[5000];
int f[5000],M,T,s;
inline int cmp(struct edge x ,struct edge y)
{
    return x.cost<y.cost;
}
int finds(int x)
{
    if(x!=f[x])
        f[x] = finds(f[x]);
    return f[x];
}
int krus()
{
    int x,y,k=0;
    for(int i=1;i<=T;i++){
        x = finds(road[i].a);
        y = finds(road[i].b);
        if(x!=y){
            s+=road[i].cost;
            if(x>y)
                f[x] = y;
            else
                f[y] = x;
        }
    }
    return s;
}
int main()
{
    while(cin>>M&&M){
        s = 0;
        T = M*(M-1)/2;
        for(int i=1;i<=T;i++){
            f[i] = i;
            cin>>road[i].a>>road[i].b>>road[i].cost;
        }
        sort(road+1,road+T,cmp);
        s = krus();
        cout<<s<<endl;
    }
    return 0;
}
//纯C语言版
#include <stdio.h>
#include <stdlib.h>
int Tree[100]; //用来保存每个节点的最上层的父亲节点,起始的根节点的父亲节点为-1
int findRoot(int x){
    if(Tree[x]==-1) return x; //说明该点的父亲节点是自己,相当于是根节点
    else{
        int tmp=findRoot(Tree[x]);//递归寻找最早的父亲节点
        Tree[x]=tmp;
        return tmp;
    }
}
struct Edge{
    int a;
    int b;
    int cost;
}edge[6000];
typedef struct Edge Edge;
int cmp(const void *x,const void *y){
    return (*(Edge*)x).cost-(*(Edge*)y).cost; //这里用<会有问题
}
int main(){
    int n;
    while(scanf("%d",&n)!=EOF && n!=0){
        for(int i=1;i<=n*(n-1)/2;i++){
            scanf("%d%d%d",&edge[i].a,&edge[i].b,&edge[i].cost);
        }
        qsort(edge+1,n*(n-1)/2,sizeof(Edge),cmp);//将路径按距离排序 每次优先取最短的路径
        for(int i=1;i<=n;i++){
            Tree[i]=-1;
        }
        int ans=0;
        for(int i=1;i<=n*(n-1)/2;i++){
            int a=findRoot(edge[i].a);
            int b=findRoot(edge[i].b);
            if(a!=b){ //如果该边的两个端点的根节点相同,说明形成了环,那么这条边舍弃
                Tree[a]=b;
                ans+=edge[i].cost;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}
                                                                                    写了最小生成树的两种方法
#include<iostream>
#include<vector>
#include<algorithm>
#include<map>
#include<queue>
using namespace std;
struct edge
{
	int start, end, length;
	edge(int s, int e, int l) :start(s), end(e), length(l) {}
};
bool comp(edge e1, edge e2)//升序排序比较函数
{
	return e1.length < e2.length;
}
struct cmp//函数对象/仿函数,用于构建小根堆
{
	bool operator()(edge e1, edge e2)
	{
		return e1.length > e2.length;
	}
};
int find_root(map<int,int>& V, int x)//检查x所在集合的根
{
	int root = x, temp;
	while (V.find(root) != V.end() && V[root] != root)
		root = V[root];
	//路径压缩:将从 x 到 根 的路径上的节点都直接指向代表这个集合的根,压缩集合树的高度
	while (V.find(x) != V.end() && V[x] != x)
	{
		temp = V[x];
		V[x] = root;
		x = temp;
	}
	return root;
}
int kruskal(vector<edge>& E, int n)//最小生成树 克鲁斯卡尔算法O(ElogE)
{
	int sum = 0, count = 0;//边权值和,边的条数
	map<int, int> V;//顶点集/并查集
	vector<edge>::iterator it = E.begin();
	while (count != n - 1)//n个顶点的树n-1条边
	{
		while (it != E.end())//边已经排序了
		{
			int a = find_root(V, it->start);
			int b = find_root(V, it->end);
			if (a != b)//不在集合中,即没有构成回路
			{
				V[b] = a;//并入集合
				sum += it->length;
				it++;
				break;
			}
			else
				it++;
		}
		count++;
	}
	return sum;
}
int prim(vector<edge>* E, int n)//堆优化的普利姆算法O(ElogV)
{
	int sum = 0, count = 0;
	vector<edge>::iterator it;
	map<int, int> V;
	V[1] = 1;//第一个节点放入顶点集中
	priority_queue<edge, vector<edge>, cmp> PQ;//优先队列/小根堆
	it = E[1].begin();
	while (it != E[1].end())//将第一个节点上的边放入堆
	{
		PQ.push(*it);
		it++;
	}
	while (count != n - 1)
	{
		while (!PQ.empty())
		{
			edge temp = PQ.top();
			int a = find_root(V, temp.start);
			int b = find_root(V, temp.end);
			if (a != b)//不构成回路
			{
				V[b] = a;//并入集合
				sum += temp.length;
				PQ.pop();
				//将以此边终点为起点的边纳入堆
				it = E[temp.end].begin();
				while (it != E[temp.end].end())
				{
					PQ.push(*it);
					it++;
				}
				break;
			}
			else
				PQ.pop();
		}
		count++;
	}
	
	return sum;
}
void test1()
{
	int n;
	vector<edge> E;//边集,kruskal算法用到边,还要排序,适合边集
	while (cin >> n && n != 0)
	{
		int num_edge = n * (n - 1) / 2;
		for (int i = 0; i < num_edge; i++)
		{
			int s, e, l;
			cin >> s >> e >> l;
			E.push_back(edge(s, e, l));
			E.push_back(edge(e, s, l));//本题输入是单向的,为了无向图prim算法增加反向边
		}
		sort(E.begin(), E.end(), comp);
		cout << kruskal(E, n) << endl;
		E.clear();
	}
}
void test2()
{
	int n;
	while (cin>>n && n != 0)
	{	
		int num_edge = n * (n - 1) / 2;
		vector<edge>* E = new vector<edge>[n + 1];//vector数组模拟邻接表
		for (int i = 0; i < num_edge; i++)
		{
			int s, e, l;
			cin >> s >> e >> l;
			E[s].push_back(edge(s, e, l));
			E[e].push_back(edge(e, s, l));
		}
		cout << prim(E, n) << endl;
	}
}
int main()
{
	//test1();
	test2();
	return 0;
} #include<iostream>
(720)#include<bits/stdc++.h>
using namespace std;
struct Edge{
	int from;
	int to;
	int cost;
	bool operator<(const Edge& e) const{
		return cost<e.cost;
	}
}; 
Edge e[101];
int height[101];
int father[101];
int find(int x){
	if(father[x]!=-1) find(father[x]);
	else return x;
}
/*两条道路相互不可达,则连接,选取此道路。若已可达,则不能添加此道路,否则成环*/
bool union_node(int m,int n){
	int x=find(m);
	int y=find(n);
	if(x==y) return false;
	else{
		if(height[x]<height[y]) father[x]=y;
		else if(height[x]>height[y]) father[y]=x;
		else{
			father[x]=y;
			height[y]++;
		}
	}	
	return true;
}
int kruskal(int num){
	int ans = 0;
	sort(e,e + num);
	for(int i = 0 ; i < num ; i++){
		int x=e[i].from;
		int y=e[i].to;
		if(union_node(x,y)) ans+=e[i].cost;
	}
	return ans;
}
int main(){
	int n;
	while(cin>>n){
		memset(father,-1,sizeof(father));
		memset(height,0,sizeof(height));
		int num=(n-1)*n/2;
		for(int i=0;i<num;i++){
			cin>>e[i].from>>e[i].to>>e[i].cost;
		}
		cout<<kruskal(num)<<endl;
	}
} #include <iostream>
#include<algorithm>
using namespace std;
int p[101];
struct edge{
int a;
int b;
int len;
}e[5000];
bool cmp(edge a,edge b){
   return a.len<b.len;
}
void inital(int n){
    for(int i=1;i<=n;i++){
        p[i]=i;
       
    }
}
int find(int x){
    if(p[x]!=x){
        p[x]=find(p[x]);
    }
    return p[x];
}
void unite(int x,int y){
    x=find(x);
    y=find(y);
    if(x!=y)   p[x]=y;
}
int kruskal(int n){
    inital(n);
    int ans=0;
    sort(e,e+n*(n-1)/2,cmp);
    for(int i=0;i<n*(n-1)/2;i++){
        int x=e[i].a,y=e[i].b;
       if(find(x)!=find(y)){
        unite(x,y);
        ans+=e[i].len;
       }
    }
    return ans;
}
int main() {
    int n;
    while(cin>>n){
        if(n==0)break;
      int m=n*(n-1)/2;
      for(int i=0;i<m;i++){
        cin>>e[i].a>>e[i].b>>e[i].len;
      }
      cout<<kruskal(n)<<endl;
    }
} #include <cstdio>
#include <iostream>
#include<vector>
#include<algorithm>
using namespace std;
int father[10001];
void InitSet(int n) {
    for (int i = 0; i < n; i++) {
        father[i] = i;
    }
}
int FindFather(int u) {
    if (u == father[u]) {
        return u;
    } else {
        father[u] = FindFather(father[u]);
        return father[u];
    }
}
void UnionSet(int r, int t) {
    r = FindFather(r);
    t = FindFather(t);
    father[r] = t;
}
struct edge {
    int u;//边的两个结点、权值
    int v;
    int w;
    edge(int _u, int _v, int _w) {
        u = _u;
        v = _v;
        w = _w;
    }
};
bool cmp(edge a,edge b){
    return a.w<b.w;//从小到大最小生成树
}
int main() {
    int n;
    while (scanf("%d", &n) != EOF) {
        vector<edge> edgev;//存储边的向量
        if(0==n){
            break;
        }
        for(int i=0;i<(n-1)*n/2;i++){
            int u,v,w;
            scanf("%d %d %d",&u,&v,&w);
            edge e(u,v,w);
            edgev.push_back(e);
        }
        InitSet(10001);
        sort(edgev.begin(),edgev.end(),cmp);
        int edgenum=0,totaledgesum=0;//边的数量与权值之和
        for(int i=0;i<edgev.size();i++){
            int u=edgev[i].u,v=edgev[i].v,w=edgev[i].w;
            if(FindFather(u)!=FindFather(v)){
                edgenum++;
                UnionSet(u,v);
                totaledgesum+=w;
                if(edgenum==n-1){ //最小树已经生成完毕
                    break;
                }
            }
        }
        printf("%d\n",totaledgesum);
    }
}
// 64 位输出请用 printf("%lld") #include<stdio.h>
#include<math.h>
#include<stdlib.h>
struct Point{
    int x;
    int y;
};
struct Edge{
    int from;
    int to;
    int length;
};
struct Point point[100];
struct Edge edge[100*99/2];
int father[100];
int heigth[100];
void initial(int n){
    int i;
    for (i = 0; i < n; i++){
        father[i] = i;
        heigth[i] = 0;
    }
        
}
int Find(int i){
        if (i != father[i]){
            father[i] = Find(father[i]);
        }
    
    return father[i];
}
void Uion(int a, int b){
    a = Find(a);
    b = Find(b);
    if (a != b){
        if (heigth[a] < heigth[b]){
            father[a] = b;
        }
        else if (heigth[a] > heigth[b])
        {
            father[b] = a;
        }
        else{
            father[b] =a;
            heigth[a]++;
        }
        
    }
}
int cmp(const void *a, const void *b){
    const struct Edge*edga = (const struct Edge*)a;
    const struct Edge*edgb = (const struct Edge*)b;
    if(edga->length < edgb->length) return -1;
    if (edga->length > edgb->length) return 1;
    return 0;
    
}
int kruskal(int n, int edgenum){
    initial(n);
    int ans = 0;
    qsort(edge, edgenum, sizeof(struct Edge), cmp);
    for (int i = 0; i < edgenum; i++){
        if (Find(edge[i].from) != Find(edge[i].to)){
            Uion(edge[i].from, edge[i].to);
                ans += edge[i].length;
        }
    }
    return ans;
}
int main(){
    int n, res;
    int a[100];
    while(scanf("%d", &n) != EOF){
        if (n == 0) break;
        for(int i = 0; i < n*(n-1)/2; i++){
            scanf("%d %d %d", &edge[i].from, &edge[i].to, &edge[i].length);
        }
        res = kruskal(n, n*(n-1)/2);
        printf("%d\n", res);
    }
    return 0;
}
 #include<iostream>
#include<map>
#include<algorithm>
using namespace std;
const int MAX=100;
int father[MAX];
int height[MAX];
struct Edge{
	int from;
	int to;
	int length;
};
Edge edge[MAX*MAX];
void Initial(int n){
	for(int i=0;i<=n;i++){
		father[i]=i;
		height[i]=0;
	}
}
int Find(int x){
	if(x!=father[x]){
		father[x]=Find(father[x]);
	}
	return father[x];
}
void Union(int x,int y){
	x=Find(x);
	y=Find(y);
	if(x!=y){
		if(height[x]<height[y]){
			father[x]=y;
		}else if(height[y]<height[x]){
			father[y]=x;
		}else{
			father[y]=x;
			height[x]++;
		}
	}
	return ;
}
bool cmp(Edge edge1,Edge edge2){
	return edge1.length<edge2.length;
}
int Kruskal(int n,int edgeNumber){
	Initial(n);
	sort(edge,edge+edgeNumber,cmp);
	int sum=0;
	for(int i=0;i<=edgeNumber;i++){
		Edge current=edge[i];
		if(Find(current.from)!=Find(current.to)){
			Union(current.from,current.to);
			sum+=current.length;
		}
	}
	return sum;
}
int main(){
	int n;
	while(cin>>n){
		if(n==0) break;
		int edgeNumber=(n-1)*n/2;
		Initial(n);
		for(int i=0;i<edgeNumber;i++){
			cin>>edge[i].from>>edge[i].to>>edge[i].length;
		}
		int sum=Kruskal(n,edgeNumber);
		cout<<sum<<endl;
	} 
}