AcWing 1146. 新的开始(超级源点+prim)
原题链接
中等
作者:
仅存老实人
,
2020-11-03 15:28:59
,
所有人可见
,
阅读 290
/*
超级发电站和n+1个点连通
超级源点0
从一个点s开始
逐步把所有点和s连通起来
每次连通时 选择当前这个点所在的连通块和外界连的边里
选择最短的一条边加入到当前的连通块中
本题
点1-点2-点3
|
点4-源点o
源点和点4的距离最小(3)
点4和点1的距离最小(2)
点1和点2\3距离最小(2)
3+2+2+2 = 9
*/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 310;
int n;
int w[N][N];
int dist[N];
bool st[N];
int prim()
{
memset(dist, 0x3f, sizeof dist);
dist[0] = 0;
int res = 0;
// n+1个点加到集合中去 循环n+1次 每次找当前距离最小值
for (int i = 0; i < n + 1; i ++ )
{
int t = -1;
for (int j = 0; j <= n; j ++ )
//没有访问过这个点j(t=-1) 或者当前最小点t比这个点j大
if (!st[j] && (t == -1 || dist[t] > dist[j]))
t = j;
// t已经加入(由于初始化时dist[0]=0 所以会从超级源点开始加)
st[t] = true;
res += dist[t];
// 枚举其他所有点 更新其他点距离
for (int j = 0; j <= n; j ++ ) dist[j] = min(dist[j], w[t][j]);
}
return res;
}
int main()
{
cin >> n;
// 在超级源点0向当前点连通的权重
for(int i=1;i<=n;i++)
{
cin >> w[0][i];
w[i][0] = w[0][i];
}
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= n; j ++ )
scanf("%d", &w[i][j]);
printf("%d\n", prim());
return 0;
}