poj2421 最小生成树

内容

Constructing Roads
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 35818 Accepted: 16112
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 个村庄,从 1 到 N 编号,你应该建造一些道路,使每两个村庄可以相互连接。 我们说两个村庄 A 和 B 是连通的,当且仅当 A 和 B 之间有一条道路,或者存在一个村庄 C,使得 A 和 C 之间有一条道路,C 和 B 是连通的。

我们知道一些村庄之间已经有一些道路,你的工作是建造一些道路,使所有村庄都连接起来,并且所有道路的长度最短。第一行是一个整数N(3 <= N <= 100),即村庄的数量。 然后是N行,其中第i个包含N个整数,这N个整数中的第j个就是i村和j村之间的距离(距离应该是[1, 1000]内的整数)。

然后有一个整数 Q (0 <= Q <= N * (N + 1) / 2)。 然后是Q行,每行包含两个整数a和b(1 <= a < b <= N),表示a村和b村之间的道路已经修好。你应该输出一个包含一个整数的行,它是连接所有村庄的所有道路的长度,并且这个值是最小的。

实现思路:

最小生成树概念:
图的所有生成树中具有边上的权值之和最小的树称为图的最小生成树。
简单来说,对于一个有n个点的图,边一定是大于等于n − 1 n-1n−1条的,最小生成树,就是在这些边中选择n − 1条出来连接所有的n个点,且这n − 1条边的边权之和是所有方案中最小的。
Prim算法构造最小生成树:
Prim算法是一种构造性算法。假设G = ( V , E ) G = (V, E)G=(V,E)是一个具有n nn个顶点的带权连通无向图,T = ( U , T E ) T = (U, TE)T=(U,TE)是G的最小生成树,其中U UU是T TT的顶点集,T E是T TT的边集,则由G GG构造从起始顶点v出发的最小生成树T的步骤如下:
(1)初始化U = { v } U = {v}U={v}。以v vv到其他顶点的所有边为候选边;
(2)重复以下步骤n − 1次,使得其他n − 1个顶点被加入到U中:
①:以顶点集U UU和顶点集V − U 之间的所有边(称为割集( U , V − U ) 作为候选边,从中挑选权值最小的边(称为轻边)加入T E ,设该边在V − U中的顶点是k ,将k 加入U 中;
②:考察当前V − U 中的所有顶点jj,修改候选边:若( k , j ) 的权值小于原来和顶点j 关联的候选边,则用( k , j )取代后者作为候选边。
本道题就是采用最小生成解法来完成
针对本道题完成一个最小生成树的算法其实并不困难只是需要改动几处,首先初始节点(1)到所有其他节点都是可以直达的这点和一般的算法题目不太一样。这样一分析这道题目只需要两个操作:寻找1的下一个最小权值节点,重新更新剩余的节点。

一点个人体悟

我现在觉得写代码,实现一个系统或者一个小题目,任何需求,最重要的是抓住主体的代码块,比如说这道题最重要最核心的部分就是上述的两个操作,前后不超过二十行代码,剩余的部分代码实现很简单,模块化的思维以及提炼核心的思维。

源代码

#include<iostream>
#include<cstdio>

int main() {
    int n, q, a[105][105], sum = 0;
    int flag[105] = { 0 };
    scanf("%d", &n);
    //n个村庄之间的距离
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            scanf("%d", &a[i][j]);
        }
    }
    scanf("%d", &q);
    //两个村庄之间建设有道路距离就等于0
    int b, c;
    for (int i = 1; i <= q; i++) {
        scanf("%d%d", &b, &c);
        a[b][c] = 0;
        a[c][b] = 0;
    }

    //最小生成树解法 这里初始起点是1
    flag[1] = 1;//第一个结点被覆盖掉
    for (int k = 1; k < n; k++) {//循环n-1次找到n个结点就可
        int min1 = -1, min_i;
        //第一步先选取下一个最小权值的节点
        for (int i = 2; i <= n; i++) {//选取下一个最小权值的结点
            if (flag[i] == 0 && (min1 == -1 || a[1][i] < min1)) {
                min1 = a[1][i];
                min_i = i;//记录被选的结点号
            }
        }

        flag[min_i] = 1;
        for (int i = 2; i <= n; i++) {//更新未覆盖结点距离
            if (flag[i] == 0 && a[1][i] > a[min_i][i]) {
                a[1][i] = a[min_i][i];
            }
        }
        sum += a[1][min_i];//加上权值
    }
    printf("%d\n", sum);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值