POJ3026 Borg Maze(最小生成树)

题目链接

题目大意:

任意两点(点表示字母)可以连线,求使所有点连通,且权值和最小。

分析:

第一感觉使3维的BFS。但写着写着,发现不对。

应当用最小生成树解法。把每个字母(即A,或S)看成一个结点,如果求出来任意两个结点间的权值,则求解即为求最小生成树。

通过暴力,对每一个字母进行BFS,求出任意两个结点的距离。然后prim.

AC代码如下:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>

using namespace std;

const int maxn = 52;
const int INF = (1<<29);

int dx[] = {0, 0, -1, 1};
int dy[] = {1, -1, 0, 0};

struct Pos {
    int x, y;
};

char G[maxn][maxn];                                     //存放地图
bool vis[maxn][maxn];                                   //深搜时用的标记数组
int num[maxn][maxn], node[110][110];                    //num表示字母编号(从0开始),node字母间的最短距离
int dis[maxn][maxn];                                    //深搜时用来记录到(sx,sy)的最短距离
int n, m, cn;


void BFS(int sx, int sy) {
    queue<Pos> Q;

    memset(vis, 0, sizeof(vis));

    Q.push((Pos){sx, sy});
    vis[sx][sy] = true;
    dis[sx][sy] = 0;

    while(!Q.empty()) {
        Pos e = Q.front(); Q.pop();
        int x = e.x, y = e.y;

        if(num[x][y] != -1)                              //(x,y)这点是字母
            node[num[sx][sy]][num[x][y]] = dis[x][y];

        for(int d=0; d<4; d++) {
            int nx = x+dx[d];
            int ny = y+dy[d];

            if(nx < 0 && ny < 0 && nx >= n && ny >= m) continue;
            if(vis[nx][ny] || G[nx][ny] == '#') continue;

            vis[nx][ny] = true;
            dis[nx][ny] = dis[x][y]+1;
            Q.push((Pos){nx, ny});
        }
    }
}

int prim(int s) {
    /*
     * cn为结点数,node为邻接矩阵
     * 任意两点间距离node[i][j]
     * 本题就是prim模板
     */

    int d[110], ans = 0;
    bool v[110];

    memset(v, false, sizeof(v));

    for(int i=0; i<cn; i++) {
        d[i] = node[s][i];
    }

    v[s] = true;
    d[s] = 0;

    for(int i=0; i<cn-1; i++) {
        int x, m=INF;
        for(int y=0; y<cn; y++) if(!v[y] && m >= d[y]) m = d[x=y];
        v[x] = true;
        ans += m;
        for(int y=0; y<cn; y++) if(!v[y] && d[y] > node[x][y]) d[y] = node[x][y];
    }

    return ans;
}

int main() {
    int T, n, m, ns;
    char tmp[200];

    scanf("%d", &T);

    while(T--) {
        scanf("%d%d", &m, &n);
        gets(tmp);                                      //discuss上说后面有多个空格
        for(int i=0; i<n; i++) {
            gets(G[i]);
        }

        cn = 0;                                         //字母的个数
        memset(num, -1, sizeof(num));

        for(int i=0; i<n; i++) {
            for(int j=0; j<m; j++) {
                if(G[i][j] == 'S' || G[i][j] == 'A') {  //对字母进行编号
                    num[i][j] = cn++;
                }

                if(G[i][j] == 'S') {                    //'S'的编号
                    ns = cn-1;
                }
            }
        }

        for(int i=0; i<n; i++) {
            for(int j=0; j<m; j++) {
                if(G[i][j] == 'A' || G[i][j] == 'S')
                    BFS(i, j);
            }
        }

        printf("%d
", prim(ns));
    }

    return 0;
}
原文地址:https://www.cnblogs.com/tanhehe/p/3253216.html