poj 2421 Constructing Roads(最小生成树 kruskal算法)

28 篇文章 1 订阅
11 篇文章 0 订阅
Constructing Roads
http://poj.org/problem?id=2421
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 19457 Accepted: 8103

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

题目:第一行给出一个数n;
然后是n行,每行有n个数,第i行第j列的数代表从i到j的路径长度;
然后再给出一个数q;
下面有q行,每行两个数a,b;代表a,b之间已经有路;
问如果使这n个村子全部连接在一块,最小还要修多少路?

kruskal算法:
求加权连通图的最小生成树的算法。kruskal算法总共选择n- 1条边,所使用的贪婪准则是:从剩下的边中选择一条不会产生环路的具有最小耗费的边加入已选择的边的集合中。
注意到所选取的边若产生环路则不可能形成一棵生成树。kruskal算法分e 步,其中e 是网络中边的数目。按耗费递增的顺序来考虑这e 条边,每次考虑一条边。当考虑某条边时,
若将其加入到已选边的集合中会出现环路,则将其抛弃,否则,将它选入。
kruskal算法可以看成并查集的操作
代码:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include<stdlib.h>
#define MAX 110
using namespace std;
struct node
{
    int a,b;
    int dis;
    node()
    {
        a=0;
        b=0;
        dis=0;
    }
};
int visit[MAX];
int f[MAX];
int cmp(const void *a,const void *b)
{
    node *p1=(node *)a,*p2=(node *)b;
    return p1->dis-p2->dis;
}
void init(int n)
{
    memset(f,-1,sizeof(f));
}
int set_find(int x)
{
    return f[x]<0?x:f[x]=set_find(f[x]);
}
int main()
{
    int n,i,j,a,b,ans,num;
    bool flag;
    //freopen("\\input.txt","r",stdin);
    //freopen("\\output.txt","w",stdout);
    scanf("%d",&n);
    {
        memset(visit,0,sizeof(visit));
        init(n);
        node map[MAX*MAX];
        for(i=1,num=0; i<=n; i++)
        {
            flag=true;
            for(j=1; j<=n; j++)
            {
                scanf("%d",&b);
                if(b==0)
                {
                    flag=false;
                    continue;
                }
                if(!flag)
                {
                    map[num].a=i;
                    map[num].b=j;
                    map[num++].dis=b;
                }
            }
        }
        ans=0;
        qsort(map,num,sizeof(map[0]),cmp);//按权值从小到大排序
        int q;
        scanf("%d",&q);
        for(i=1; i<=q; i++)
        {
            scanf("%d%d",&a,&b);
            if(set_find(b)!=set_find(a))//判断是否在同一个树上
                f[set_find(b)]=set_find(a);//合并
        }
        int p1,p2;
        for(i=0; i<num; i++)
        {
            p1=set_find(map[i].a);
            p2=set_find(map[i].b);//合并操作完全是并查集的操作
            if(p1==p2)
                continue;
            f[p2]=p1;
            ans+=map[i].dis;//将权值累加
        }
        printf("%d\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值