题目戳这里
题目大意 : 给出测试数据组数 t ,接下来每组数据给出列数 n ,行数 m ,然后是一个n * m 的迷宫,#代表墙, S 为起始点,A 为外星人的位置,现在要求从S出发到达所有外星人的位置,而你自己有一个能力是可以再为 S 或 A 的位置分成多个组从不同的方向前进,要求找出最短的行走路线,其中要注意一个组分组前走过的路径只算一次,分组之后二者走过的路径长度分开算。输出最短的路径长度。
大致思路 : 根据题意对于寻找外星人的小组每次只能在 A 或 S 出分组走不同路线,既然这样可以将 A 和 S 作为定点,将对应的顶点在迷宫中的最短,路径长度最为权值,生成一个图,现在就是你从这个图的一个顶点出发,选出一些边是的这些边形成的图的边权值和最小,且这个图覆盖到所有原来图的顶点,也就是找出这个图的最小生成树。
对于图形的边权值,用 bfs 算法找到对应的最短距离,对于所有的顶点对搜索之后形成一个图,用 Kruskal 算法找出最小生成树的权值和即可。
陷阱 : POJ 对于此题给出的输入数据,在输入行数和列数之后会有一段空格,所以在读取行数和列数之后,不能用 getchar() 获取换行符后就开始读取#等字符,而应用gets()来终结掉前一行的结尾的干扰空格。
样例输入:
1
6 5 ← 这里有空格
#####
#A#A##
# # A#
#S ##
#####
样例输出:
8
刚好这次复习Prim算法的时候有做了一次这一题,沿着上次的想法,吧之前的bfs处理的部分改进了一下(利用dx和dy数组使得代码简化),同时在原来的Kruskal之后又重新用Prim算法做了一次,算是熟悉一下平常我用的比较少的Prim
代码如下:
Kruskal算法的方法:
Result : Accepted Memory : 340 KB Time : 32 ms
/* * Author: Gatevin * Created Time: 2014/7/17 10:08:49 * File Name: test.cpp */ #include<iostream> #include<sstream> #include<fstream> #include<vector> #include<list> #include<deque> #include<queue> #include<stack> #include<map> #include<set> #include<bitset> #include<algorithm> #include<cstdio> #include<cstdlib> #include<cstring> #include<cctype> #include<cmath> #include<ctime> #include<iomanip> using namespace std; const double eps(1e-8); typedef long long lint; int T,row,col; char maz[51][51]; char hehe[100]; int V,E; int r[10000]; int u[10000]; int v[10000]; int w[10000]; int f[110]; int step[51][51]; int number[51][51]; int dx[5] = {0, 1, 0, 0, -1}; int dy[5] = {0, 0, -1, 1, 0}; queue <pair<int, int> > cord; const int inf = 0x3f3f3f3f; bool cmp(const int& i, const int& j) { return w[i] < w[j]; } int find(int i) { if(i != f[i]) { f[i] = find(f[i]); } return f[i]; } int Kruskal() { for(int i = 1; i <= E; i++) r[i] = i; for(int i = 1; i <= V; i++) f[i] = i; int answer = 0; sort(r + 1, r + E + 1, cmp); for(int i = 1; i <= E; i++) { int e = r[i]; int rx = find(u[e]); int ry = find(v[e]); if(rx != ry) { answer += w[e]; f[rx] = ry; } } return answer; } bool inMaze(int x, int y) { if(x <= row && x >= 1 && y <= col && y >= 1) { return true; } else { return false; } } void bfs(int x, int y) { while(!cord.empty()) { cord.pop(); } cord.push(make_pair(x, y));//当前入队的坐标 for(int i = 1; i <= row; i++) { for(int j = 1; j <= col; j++) { step[i][j] = inf; } } step[x][y] = 0; while(!cord.empty()) { pair <int, int> now = cord.front(); cord.pop(); for(int i = 1; i <= 4; i++) { if(inMaze(now.first + dx[i], now.second + dy[i]) && maz[now.first + dx[i]][now.second + dy[i]] != '#') { if(step[now.first + dx[i]][now.second + dy[i]] > step[now.first][now.second] + 1)//这里每个格子最多更新一次 { step[now.first + dx[i]][now.second + dy[i]] = step[now.first][now.second] + 1; if(maz[now.first + dx[i]][now.second + dy[i]] != 'A' && maz[now.first + dx[i]][now.second + dy[i]] != 'S')//到达A或S就是端点了 { cord.push(make_pair(now.first + dx[i], now.second + dy[i])); } else { E++;//建边 u[E] = number[x][y]; v[E] = number[now.first + dx[i]][now.second + dy[i]]; w[E] = step[now.first + dx[i]][now.second + dy[i]]; } } } } } return; } int main() { scanf("%d",&T); while(T--) { E = 0; scanf("%d %d",&col,&row); memset(number, 0, sizeof(number)); V = 0; for(int i = 1; i <= row; i++) { gets(hehe); for(int j = 1; j <= col; j++) { scanf("%c",&maz[i][j]); if(maz[i][j] == 'A' || maz[i][j] == 'S') { V++; number[i][j] = V;//给点编号 } } } for(int i = 1; i <= row; i++) { for(int j = 1; j <= col; j++) { if(maz[i][j] == 'A' || maz[i][j] == 'S') { bfs(i, j);//对于每个点都去找边 } } } int answer = Kruskal(); printf("%d\n",answer); } return 0; }
Result : Accepted Memory : 268 KB Time : 32 ms
/* * Author: Gatevin * Created Time: 2014/7/17 10:08:49 * File Name: test.cpp */ #include<iostream> #include<sstream> #include<fstream> #include<vector> #include<list> #include<deque> #include<queue> #include<stack> #include<map> #include<set> #include<bitset> #include<algorithm> #include<cstdio> #include<cstdlib> #include<cstring> #include<cctype> #include<cmath> #include<ctime> #include<iomanip> using namespace std; const double eps(1e-8); typedef long long lint; int T,row,col; char maz[51][51]; char hehe[100]; int V; int step[51][51]; int number[51][51]; int dx[5] = {0, 1, 0, 0, -1}; int dy[5] = {0, 0, -1, 1, 0}; queue <pair<int, int> > cord; vector <pair<int, int> > g[110]; int dis[110]; bool vis[110]; const int inf = 0x3f3f3f3f; bool inMaze(int x, int y) { if(x <= row && x >= 1 && y <= col && y >= 1) { return true; } else { return false; } } void bfs(int x, int y) { while(!cord.empty()) { cord.pop(); } cord.push(make_pair(x, y)); for(int i = 1; i <= row; i++) { for(int j = 1; j <= col; j++) { step[i][j] = inf; } } step[x][y] = 0; while(!cord.empty()) { pair <int, int> now = cord.front(); cord.pop(); for(int i = 1; i <= 4; i++) { if(inMaze(now.first + dx[i], now.second + dy[i]) && maz[now.first + dx[i]][now.second + dy[i]] != '#') { if(step[now.first + dx[i]][now.second + dy[i]] > step[now.first][now.second] + 1)//每个格子最多更新一次 { step[now.first + dx[i]][now.second + dy[i]] = step[now.first][now.second] + 1; if(maz[now.first + dx[i]][now.second + dy[i]] != 'A' && maz[now.first + dx[i]][now.second + dy[i]] != 'S')//到达顶点就不入队了 { cord.push(make_pair(now.first + dx[i], now.second + dy[i])); } else { g[number[x][y]].push_back(make_pair(number[now.first + dx[i]][now.second + dy[i]], step[now.first + dx[i]][now.second + dy[i]])); }//邻接表建图 } } } } return; } int Prim() { memset(vis, 0, sizeof(vis)); fill(dis + 1, dis + V + 1, inf); dis[1] = 0; int ret = 0; for(int i = 1; i <= V; i++) { int mark = -1; for(int j = 1; j <= V; j++) { if(!vis[j]) { if(mark == -1) { mark = j; } else { if(dis[mark] > dis[j]) { mark = j; } } } } if(mark == -1) break; vis[mark] = 1; ret += dis[mark]; for(unsigned int j = 0; j < g[mark].size(); j++) { if(!vis[g[mark][j].first]) { int x = g[mark][j].first; dis[x] = min(dis[x], g[mark][j].second); } } } return ret; } int main() { scanf("%d",&T); while(T--) { scanf("%d %d",&col,&row); memset(number, 0, sizeof(number)); V = 0; for(int i = 1; i <= row; i++) { gets(hehe); for(int j = 1; j <= col; j++) { scanf("%c",&maz[i][j]); if(maz[i][j] == 'A' || maz[i][j] == 'S') { V++; number[i][j] = V; } } } for(int i = 1; i <= row; i++) { for(int j = 1; j <= col; j++) { if(maz[i][j] == 'A' || maz[i][j] == 'S') { bfs(i, j);//找边 } } } int answer = Prim(); printf("%d\n",answer); for(int i = 1; i <= V; i++) { if(!g[i].empty()) { g[i].clear(); } } } return 0; }