HNACM(八)D-引水工程

传送门

最小生成树算法

首先找到一个自建水库最少费用的 然后以此为根本 找到与之相关的边
还要注意当权值相等时的处理方法

#include <bits/stdc++.h> 
#define N 310
#define ll long long
#define MAX 11111
using namespace std;
int n, w[N], p[N][N], water[N];
//w[N]是 每个地方自建水库所需的费用
//water[N]是存放已经解决用水问题的地方 
bool vis[N];
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;
}

你可能感兴趣的:(HNACM(八)D-引水工程)