HNACM(八)D-引水工程

来源:互联网 发布:微信公众号对接数据库 编辑:程序博客网 时间:2024/04/27 19:50

传送门


最小生成树算法

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

#include <bits/stdc++.h> #define N 310#define ll long long#define MAX 11111using 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;}

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

感谢@Dart 提供思路

#include <iostream>#include <cstdio>#define MAXN 310using 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;}
0 0