您的位置:首页 > 其它

HNACM(八)D-引水工程

2016-04-08 17:35 357 查看
传送门

最小生成树算法

首先找到一个自建水库最少费用的 然后以此为根本 找到与之相关的边

还要注意当权值相等时的处理方法

#include <bits/stdc++.h>
#define N 310
#define ll long long
#define MAX 11111
using namespace std;
int n, w
, p

, water
;
//w
是 每个地方自建水库所需的费用
//water
是存放已经解决用水问题的地方
bool vis
;
int prim(int pos, int sum){
int i, j, k, cur = 0;
memset(vis, false, sizeof(vis));
memset(water, 0, sizeof(water));
water[cur++] = pos;
vis[pos] = true;
while(cur < n){
int mindist = MAX;
int min1 = MAX;
int u = -1;
for (i = 0; i < cur; i++){//遍历所有的已经解决用水问题的点
for (j = 0; j < n; j++){
if (!vis[j] && j != water[i]){
if (mindist > p[water[i]][j]){ //未解决问的点,找出从其他地方引水的最小费用
mindist = p[water[i]][j];
min1 = w[j];
u = j;
}else if (mindist == p[water[i]][j] && min1 > w[j]){//如果当前最小值和权值相等,比较自建费用
min1 = w[j];
u = j;
}
}
}
}
vis[u] = true;
water[cur++] = u;
sum += min(min1, mindist);//去自建费用和从其他地方引水的费用的较小者
}
return sum;
}
int main(){
#ifndef ONLINE_JUDGE
//  freopen("1.txt", "r", stdin);
//  freopen("d.in", "r", stdin);
//  freopen("d1.out", "w", stdout);
#endif
int i, j, k, K, Min, pos;
scanf("%d", &K);
while(K--){
scanf("%d", &n);
Min = MAX;
for (i = 0; i < n; i++){
scanf("%d", &w[i]);
if (Min > w[i]){//先寻找自建水库的费用最小的地方
pos = i;
Min = w[i];
}
}
for (i = 0; i < n; i++){
for (j = 0; j < n; j++){
scanf("%d", &p[i][j]);
}
}
printf("%d\n", prim(pos, Min));//先从自建水库最小的地方开始
}
return 0;
}


另一种方法,把自建费用当成结点0到结点i的费用,然后用最下生成树算法

感谢@Dart 提供思路

#include <iostream>
#include <cstdio>
#define MAXN 310
using namespace std;
int g[MAXN][MAXN], dis[MAXN];
bool vis[MAXN];
const int INF = 0x3f3f3f3f;
int n;
int prim(int st){
int i, j, k;
for (i = 0; i <= n; i++){
vis[i] = false;
dis[i] = g[st][i];
}
dis[st] = 0;
vis[st] = true;
int sum = 0;
for (i = 1; i <= n; i++){
int Min = INF;
int v = -1;
for (j = 0; j <= n; j++){
if (!vis[j] && Min > dis[j]){
v = j;
Min = dis[j];
}
}
vis[v] = true;
sum += Min;
for (j = 0; j <= n; j++){
if (!vis[j] && g[v][j] < dis[j]){
dis[j] = g[v][j];
}
}
}
return sum;
}
int main(){
int i, j, k, T;
scanf("%d", &T);
while(T--){
scanf("%d", &n);
for (i = 1; i <= n; i++){
scanf("%d", &g[0][i]);
g[i][0] = g[0][i];
}
for (i = 1; i <= n; i++){
for (j = 1; j <= n; j++){
scanf("%d", &g[i][j]);
}
}
printf("%d\n", prim(0));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: