POJ 2421 Constructing Roads 最小生成树 Kruskal算法

基本思想:就是维护一个生成森林。每次将一条权最小的边加入子图T中,并保证不形成圈。如果当前弧加入后不形成圈,则加入这条弧,如果当前弧加入后会形成圈,则不加入这条弧,并考虑下一条弧。

算法:

1.将E中的边按权从小到大排序,。

2.i=i+1,若i>m,结束,此时G没有生成树;否则判断是否含圈,是则转2,否则转3。

3.若|T|=N,结束,此时T为G的最小生成树。

      分离集合(disjoint set),可用并查集实现。由于排序是的。所以复杂度为O(mlogm+ma(n))。

最小生成树就是在一个带权的无向连通图中寻求最小的一类生成树。

kruskal伪代码

按照边权递增的顺序排序的边集e

建立最小生成树的权和ans=0

for k :1 to m ///枚举m条边

   if 第k条边(u,v)两个端点分属于两颗子树

u结点所在的子树并入j结点所在的子树,ans+=k的边长

Constructing Roads
Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 21253   Accepted: 8975

Description

There are N villages, which are numbered from 1 to N, and you should build some roads such that every two villages can connect to each other. We say two village A and B are connected, if and only if there is a road between A and B, or there exists a village C such that there is a road between A and C, and C and B are connected. 

We know that there are already some roads between some villages and your job is the build some roads such that all the villages are connect and the length of all the roads built is minimum.

Input

The first line is an integer N (3 <= N <= 100), which is the number of villages. Then come N lines, the i-th of which contains N integers, and the j-th of these N integers is the distance (the distance should be an integer within [1, 1000]) between village i and village j. 

Then there is an integer Q (0 <= Q <= N * (N + 1) / 2). Then come Q lines, each line contains two integers a and b (1 <= a < b <= N), which means the road between village a and village b has been built.

Output

You should output a line contains an integer, which is the length of all the roads to be built such that all the villages are connected, and this value is minimum.

Sample Input

3
0 990 692
990 0 179
692 179 0
1
1 2

Sample Output

179

Source

PKU Monthly,kicc

[Submit]   [Go Back]   [Status]   [Discuss]

题目给出n个村庄及每个村庄的距离

然后给出m对关系(x,y)表示x,y之间已经建立道路

问最小要建立多少长度的路使得新建的公路最短且所有村庄连通

ACcode:

#pragma warning(disable:4786)//使命名长度不受限制
#pragma comment(linker, "/STACK:102400000,102400000")//手工开栈
#include <map>
#include <set>
#include <queue>
#include <cmath>
#include <stack>
#include <cctype>
#include <cstdio>
#include <cstring>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
#define rd(x) scanf("%d",&x)
#define rd2(x,y) scanf("%d%d",&x,&y)
#define rds(x) scanf("%s",x)
#define rdc(x) scanf("%c",&x)
#define ll long long int
#define maxn 100005
#define mod 1000000007
#define INF 0x3f3f3f3f //int 最大值
#define FOR(i,f_start,f_end) for(int i=f_start;i<=f_end;++i)
#define MT(x,i) memset(x,i,sizeof(x))
#define PI  acos(-1.0)
#define E  exp(1)
using namespace std;
struct  Edge{
    int u,v,w;
    Edge(){}
    Edge(int a,int b,int c){
        u=a;v=b;w=c;
    }
    friend bool operator <(Edge a,Edge b){
        return a.w<b.w;
    }
}my[maxn];
int fa[maxn];///表示父亲结点
int find_fa(int x){///并查集
    return x==fa[x]?x:(fa[x]=find_fa(fa[x]));
}
int main(){
    int n,m,x,y,data,cnt;
    while(rd(n)!=EOF){
        cnt=0;
        MT(my,0);
        FOR(i,1,n*n)
            fa[i]=i;
        FOR(i,1,n)
            FOR(j,1,n){
                rd(data);
                if(i<j)///只需要存下三角形
                my[++cnt]=Edge(i,j,data);
            }
        rd(m);
        FOR(i,1,m){
            rd2(x,y);
            fa[find_fa(x)]=find_fa(y);
        }
        sort(my+1,my+cnt+1);
        int sum=0;
        FOR(i,1,cnt){
            x=find_fa(my[i].u);
            y=find_fa(my[i].v);
            if(x!=y){///如果没有连通
                sum+=my[i].w;
                fa[y]=x;
            }
        }
        printf("%d\n",sum);
    }
    return 0;
}
/*
3
0 990 692
990 0 179
692 179 0
1
1 2
*/


你可能感兴趣的:(C++,最小生成树,poj,kruskal)