练习四1001

Problem A

Time Limit : 2000/1000ms (Java/Other)   Memory Limit :65536/32768K (Java/Other)

 

Problem Description

There are Nvillages, which are numbered from 1 to N, and you should build some roads suchthat every two villages can connect to each other. We say two village A and Bare connected, if and only if there is a road between A and B, or there existsa village C such that there is a road between A and C, and C and B areconnected. <br><br>We know that there are already some roadsbetween some villages and your job is the build some roads such that all thevillages are connect and the length of all the roads built isminimum.<br>

 

 

Input

The first line isan integer N (3 <= N <= 100), which is the number of villages. Then comeN lines, the i-th of which contains N integers, and the j-th of these Nintegers is the distance (the distance should be an integer within [1, 1000])between village i and village j.<br><br>Then there is an integer Q(0 <= Q <= N * (N + 1) / 2). Then come Q lines, each line contains twointegers a and b (1 <= a < b <= N), which means the road betweenvillage a and village b has been built.<br>

 

 

Output

You should outputa line contains an integer, which is the length of all the roads to be builtsuch that all the villages are connected, and this value is minimum. <br>

 

 

Sample Input

3

0 990 692

990 0 179

692 179 0

1

1 2

 

 

Sample Output

179

 

题意:给出任意两个城市之间建一条路的时间,给出哪些城市之间已经建好,问最少还要多少时间使所有的城市连通?

解题思路:已经建好的城市之间需要的时间设为0,就是求最小生成树的权值和了。

prim 最小生成树算法

过程:prim算法将图分为两部分,假设原顶点集为V,将其分为S和V-S两部分,S为已经确定在最小生成树上的顶点,

开始时,将任意一个顶点加入到S,然后每次在V-S中寻找距离S中的点最近的点。作为下一个加入最小生成树上的点。

所有N个节点都加入到最小生成树中时,最小生成树构造完毕。

 

实现:对于邻接矩阵构造的图,可以用low[N]保存每个顶点到已加入生成树中所有点的最小距离。

每次寻找这个距离最小的一个点加入最小生成树中。再根据这个点的距离更新其它未加入生成树中的点。

直到所有的点都加入到最小生成树中。

 

 

 

#include <stdio.h>
#include <string.h>
#include <iostream>
#define inf 1000000
using namespace std;
 
int g[210][210];
int low[210];
int vis[210]; // 表示该点是否已经加入最小生成树中
int n;
 
int prim() {
    for (int i=0; i<n; ++i) {
        low[i] = g[0][i];
    }
 
    int ans = 0;
    memset(vis, 0, sizeof(vis));
    vis[0] = 1;
 
    for (int i=1; i<n; ++i) { // 循环n-1次,找剩下的n-1个点。
        int k = -1, mindis = inf;
        for (int j=0; j<n; ++j) { // 循环找当前剩下的点中 距离最小生成树点集距离最短的点。
            if (!vis[j] && low[j] < mindis) {
                mindis = low[j];
                k = j;
            }
        }
 
         if (k == -1) return -1;
         vis[k] = 1; // 加入最小生成树点集
         ans += mindis;
 
         for (int j=0; j<n; ++j) { // 更新没加入最小生成树的点中 距离是否会缩短。
            /*if (!vis[j] && low[j] > low[k] + g[k][j]) {
                    low[j] = low[k] + g[k][j];
            }*/
 
             if (!vis[j] && low[j] > g[k][j]) { // 上面的if是错的。low数组存储的距离是当前点到生成树中所有点距离最小的的点。
                    low[j] = g[k][j]; // 因为这个点加入最小生成树集合中,可以和其中任意一个点连一条边。
            }
        }
    }
    return ans;
}
 
 
int main() {
    int q;
    while(cin >> n) {
        for (int i=0; i<n; ++i) {
            for (int j=0; j<n; ++j) {
                cin >> g[i][j];
            }
        }
 
        cin >> q;
        for (int i=0; i<q; ++i) {
            int a, b;
            cin >> a >> b;
            a--, b--;
            g[a][b] = 0;
            g[b][a] = 0;
        }
 
        int ans = prim();
        cout << ans << endl;
    }
    return 0;
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值