题目链接: http://poj.org/problem?id=3026
题意:一对警察(S)抓捕外星人(A),‘#’代表墙,‘_’(空格)代表可以通过的路,从S处出发,问最少走多长的路可以把外星人全部KO了!注意:当他们在S处或是当抓捕到某个外星人以后,可以分开成几个队伍向周围继续抓捕,总的路程等于每支队伍的总和!
#include <cstdio> #include <cstring> #include <queue> #include <iostream> #define N 130 #define INF 0x3f3f3f3f using namespace std; int n, k; bool vis[N*N]; int dis[N][N], lostcow[N*N]; int map[N][N], cost[N][N]; char str[N][N]; int dx[] = {0, 0, 1, -1}, dy[] = {1, -1, 0, 0}; void bfs(int x, int y) { int tx, ty, i, ttx, tty; queue<pair<int, int> >Q; memset(dis, 0, sizeof(dis)); Q.push(make_pair(x, y)); dis[x][y] = 0; while(!Q.empty()) { tx = Q.front().first, ty = Q.front().second; Q.pop(); if(map[tx][ty]) cost[map[x][y]][map[tx][ty]] = dis[tx][ty];/* cost用于存字母和字母间的权值 */ for(i = 0; i < 4; i++) { ttx = tx + dx[i], tty = ty + dy[i]; if(ttx >= 0 && ttx < k && tty >= 0 && tty < n) { if(str[ttx][tty] == '#' || dis[ttx][tty]) continue; dis[ttx][tty] = dis[tx][ty] + 1; Q.push(make_pair(ttx, tty)); } } } } int prim(int nn) { int sum = 0, i, j, m; memset(vis, 0, sizeof(vis)); for(i = 1; i <= nn; i++) lostcow[i] = cost[1][i]; vis[1] = 1; for(i = 1; i < nn; i++) { m = 1; int min = INF; for(j = 1; j <= nn; j++) if(!vis[j] && lostcow[j] < min) { min = lostcow[j]; m = j; } vis[m] = 1; if(min != INF) sum += min; for(j = 1; j <= nn; j++) if(!vis[j] && lostcow[j] > cost[m][j]) lostcow[j] = cost[m][j]; } return sum; } int main() { int t, i, j; scanf("%d", &t); while(t--) { int num = 1; memset(map, 0, sizeof(map)); memset(cost, 0, sizeof(cost)); scanf("%d%d", &n, &k); gets(str[0]);/* 用getchar()不行 */ for(i = 1; i <= k; i++) { gets(str[i]); for(j = 1; j <= n; j++) if(str[i][j] == 'A' || str[i][j] == 'S')/* 字母和字母之间建最小生成树 */ map[i][j] = num++; } for(i = 1; i <= k; i++) for(j = 1; j <= n; j++) if(map[i][j]) bfs(i, j);/* 求每个字母之间的权值 */ printf("%d\n", prim(num-1)); } return 0; }