Constructing Roads(最小生成树,Prim 普里姆)

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.

题意:
先输入N,再输入N*N阶邻接矩阵。
邻接矩阵表示i到j的距离。
然后输入q表示有q组是连接着的,
然后输入q行,每行两个数字,表示ij连接
求 要把n个都连接需要的最短距离。
这里使用普里姆Prim,即使用邻接矩阵。

Sample Input

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

Sample Output

179

基本思想:将顶点之间连接权值存在一个二维数组中,没有连接两个顶点之间为极大值,循环访问所有顶点,如已经得到该顶点与其它顶点连接的最小权值,则将其标记为1,不做重复访问。

代码实现:

#include<iostream>
#include<cstring>
using namespace std;
const int N=110;
const int INF=0x3f3f3f3f;   //表示无穷大。
int n,result;
int map[N][N],dis[N],vis[N];
void Prim()
{
    int i;
    for(i=1; i<=n; i++)
    {
        dis[i]=map[1][i];
        vis[i]=0;
    }
    dis[1]=0;
    vis[1]=1;
    int j,k,tmp;
    for(i=1; i<=n; i++)
    {
        tmp=INF;
        for(j=1; j<=n; j++)
            if(!vis[j]&&tmp>dis[j])
            {
                k=j;
                tmp=dis[j];
            }
        if(tmp==INF)
            break;
        vis[k]=1;
        result+=dis[k];
        for(j=1; j<=n; j++)
            if(!vis[j]&&dis[j]>map[k][j])
                dis[j]=map[k][j];
    }
}
int main()
{
    while(cin>>n)
    {
        int i,j;
        for(i=1; i<=n; i++)
            for(j=1; j<=n; j++)
                cin>>map[i][j];
        int q,a,b;
        cin>>q;
        while(q--)
        {
            cin>>a>>b;
            map[a][b]=map[b][a]=0;
        }
        result=0;
        Prim();
        cout<<result<<endl;
    }
    return 0;
}

1、0x3f3f3f3f的十进制是1061109567,也就是10的9次方级别的(和0x7fffffff一个数量级),而一般场合下的数据都是小于10^9的,所以它可以作为无穷大使用而不致出现数据大于无穷大的情形。

2、由于一般的数据都不会大于10^9,所以当我们把无穷大加上一个数据时,它并不会溢出,这就满足了“无穷大加一个有穷的数依然是无穷大”,事实上0x3f3f3f3f+0x3f3f3f3f=2122219134,这非常大但却没有超过32-bit int的表示范围,所以0x3f3f3f3f还满足了我们“无穷大加无穷大还是无穷大”的需求。

3、0x3f3f3f3f还有一个好处:如果我们想要将某个数组清零,我们通常会使用memset(a,0,sizeof(a))这样的代码来实现,但是当我们想将某个数组全部赋值为无穷大时(例如解决图论问题时邻接矩阵的初始化),就不能使用memset函数而得自己写循环了,这是因为memset是按字节操作的,它能够对数组清零是因为0的每个字节都是0。如果我们将无穷大设为0x3f3f3f3f,0x3f3f3f3f的每个字节都是0x3f,所以要把一段内存全部置为无穷大,我们只需要memset(a,0x3f,sizeof(a))。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

为君倾此杯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值