kuangbin 最小生成树专题 - ZOJ - 1586 QS Network (朴素 Prim算法 模板题)

kuangbin 最小生成树专题 - ZOJ - 1586 QS Network (朴素 Prim算法 模板题)

总题单 week 3 [kuangbin带你飞] 题单 最小生成树 + 线段树 Click here ~~
https://blog.csdn.net/m0_46272108/article/details/108980362

Description
想用路由器把N个地方连接起来,给定N个路由器安装点,接下来的N个数字表示在某地安装一个路由器的费用。再接下来N*N的矩阵表示两地进行连接时的花费。每个路由器只能用一次,例如在AB之间连接了,就需要分别在A和B购买一个路由器,然后再把他们连起来,然后再想在AC之间连接,A就必须要再买一个路由器,不能重复使用同一个路由器,求他们的最小花费

Input
T组输入。输入N代表需要N地互联,下面一行有N个数字,代表在第i个地方安装一个路由器的费用。下面N行为一个矩阵,代表第i个地方到第j个地方连接起来所需费用。 保证所有数字不超过1000。
Output
每组输出一个结果

Sample Input

1
3
10 20 30
0 100 200
100 0 300
200 300 0

Sample Output

370

理解 朴素Prim算法 即可 (代码有详细解释)
关于朴素Prim算法,可以查看这篇文章(内有模板题及图文详解):
图论 —— 最小生成树(朴素Prim原理及模板题) https://blog.csdn.net/m0_46272108/article/details/108929358

注意输入输出!!!!

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>

#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define ll long long
//#define int ll
#define inf 0x3f3f3f3f
using namespace std;
int read()
{
	int w = 1, s = 0;
	char ch = getchar();
	while (ch < '0' || ch>'9') { if (ch == '-') w = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { s = s * 10 + ch - '0';    ch = getchar(); }
	return s * w;
}
//最大公约数
int gcd (int x,int y) {
    if(x<y) swap(x,y);//很多人会遗忘,大数在前小数在后
    //递归终止条件千万不要漏了,辗转相除法
    return x % y ? gcd(y, x % y) : y;
}
//计算x和y的最小公倍数
int lcm (int x,int y) {
    return x * y / gcd(x, y);//使用公式
}
//------------------------ 以上是我常用模板与刷题几乎无关 ------------------------//
const int N = 1010;
int g[N][N];//边的权值
int st[N];
int dist[N];
int num[N];//点的权值
int k;//数据组数
int n;//图结点的数量

int Prim()
{
    //存最小生成树里面所有长度之和
    int res = 0;
    
    for(int i = 1; i < n; i++) {
        //找到集合外,距离最短的点
        int minn = inf;
        int t;
        for(int j = 1; j <= n; ++j) {
            //在集合外
            if (!st[j] && minn > dist[j]) {
                minn = dist[j];
                t = j;
            }
        }
            

        res += dist[t];
        
        //将点加到树里面去。
        st[t] = true;
        /* 这里要先更新再累加,不然会出现自环问题,最小生成树是不存在环的。*/
        //用t更新一下,其他点到 集合 的距离
        for (int j = 1; j <= n; ++j) {
            dist[j] = min(dist[j], g[t][j]);
        }
    }
    return res;
}
int main()
{
    scanf("%d",&k);
    while(k--)
    {
        //图结点的数量
        n = read();
        //点的权值
        for (int i = 1; i <= n; ++i) {
            scanf("%d", &num[i]);
        }
        
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= n; ++j) {
                g[i][j] = read();
                g[i][j] += num[i] + num[j];
            }
        }
        
        memset(st, false, sizeof st);
        //将1放进生成树
        st[1] = true;
        for (int i = 1; i <= n; ++i) {
            dist[i] = g[i][1];
        }
        printf("%d\n", Prim());
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值