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;
}