测评会员优惠活动进行中 · 开通 VIP,有效期内测评不限次 VIP 优惠中 · 测评不限次 立即查看

A41759. 冠军之路当训练师眼神对上的那一刻,就会开始对战。lxz来到了冠军之路的山洞中。山洞的地图是一个N*M的矩形。在地图中,'.'代表可以行走的地面,'#'代表无法行走的岩石。'I'代表山洞的入口,即lxz现在所在的位置。'O'表示冠军之路的出口。lxz可以向上下左右四个方向行走。矩形的四周都是山洞的岩石,无法行走。冠军之路中有一些精英训练师,他们可能面向上、下、左、右四个方向,在地图上用'w','a…

填空题 困难

题目描述

冠军之路

当训练师眼神对上的那一刻,就会开始对战。

lxz来到了冠军之路的山洞中。山洞的地图是一个N*M的矩形。在地图中,'.'代表可以行走的地面,'#'代表无法行走的岩石。'I'代表山洞的入口,即lxz现在所在的位置。'O'表示冠军之路的出口。lxz可以向上下左右四个方向行走。矩形的四周都是山洞的岩石,无法行走。

冠军之路中有一些精英训练师,他们可能面向上、下、左、右四个方向,在地图上用'w','a','s','d'表示,其中'w'表示向上。's'表示向下。'a'表示向左。'd'表示向右(这些位置不可行走)。如果lxz出现在精英训练师正对方向的一条线上,且没有被岩石或其他精英训练师阻挡,那么lxz就会与这个精英训练师进行对战。每位训练师只会与lxz对战一次。

为了通过冠军之路,lxz必须击败所有精英训练师。lxz希望找到一条击败所有精英训练师并走到冠军之路出口的最短路径。

输入

第一行是两个整数,N, M表示地图的大小。 0 < N, M <= 100 接下来是N行,每行M个字符,代表冠军之路的地图。训练师的个数不超过8

输出

一个整数,表示击败所有精英训练师并走到冠军之路出口的最短路径的长度。如果无法击败所有精英训练师或者无法到达出口,输出-1。

样例输入

3 3

Id.

...

Oa#

样例输出

8

参考答案

#include <algorithm> #include <iostream> #include <limits> #include <queue> #include <vector> using namespace std; /* 3 3 Id. ... Oa# */ struct point { int x, y; point(int x, int y) : x(x), y(y) {} point() : x(0), y(0) {} bool operator==(const point &p) const { return x == p.x && y == p.y; } bool operator<(const point &p) const { if (x == p.x) return y < p.y; return x < p.x; } }; struct item { point pt; char c; item(point p, char c) { pt.x = p.x; pt.y = p.y; this->c = c; } }; int direct[4][2] = {{0, 1}, {1, 0}, {-1, 0}, {0, -1}}; int a[105][105]; char d[105][105]; int pass[105][105]; vector<vector<point>> pts; vector<item> base; point bp, ep; int n, m; int bfs(point from, point to) { queue<point> q; char path[105][105] = {0}; q.push(from); int ans = 0; while (q.size()) { // TODO int size = q.size(); for (int k = 0; k < size; k++) { point cur = q.front(); q.pop(); path[cur.x][cur.y] = 1; if (cur == to) { return ans; } for (int i = 0; i < 4; i++) { point dst; dst.x = cur.x + direct[i][0]; dst.y = cur.y + direct[i][1]; if (dst.x >= n || dst.x < 0) continue; if (dst.y > m || dst.y < 0) continue; if (path[dst.x][dst.y] == 0 && (d[dst.x][dst.y] == '.' || d[dst.x][dst.y] == 'O' || d[dst.x][dst.y] == 'I')) { q.push(dst); } } } ans++; } return 0; } vector<point> getpoints(char pos, point p) { vector<point> res; string ss = ".IO"; if (pos == 'w') { for (int i = p.x - 1; i >= 0; i--) if (ss.find(d[i][p.y]) != string::npos) res.push_back(point(i, p.y)); else break; } if (pos == 's') { for (int i = p.x + 1; i < m; i++) if (ss.find(d[i][p.y]) != string::npos) res.push_back(point(i, p.y)); else break; } if (pos == 'a') { for (int i = p.y - 1; i >= 0; i--) if (ss.find(d[p.x][i]) != string::npos) res.push_back(point(p.x, i)); else break; } if (pos == 'd') { for (int i = p.y + 1; i < n; i++) if (ss.find(d[p.x][i]) != string::npos) res.push_back(point(p.x, i)); else break; } return res; } /* void showpath(int i, int j) { if (i == j) return; if (pass[i][j] == 0) { printf("%d -> %d \n",i , j); route.push_back(j); } else { showpath(i, pass[i][j]); showpath(pass[i][j], j); } } */ int getMinBfs(point pt, vector<int> &idx, vector<int> &p, vector<vector<point>> pts) { int minval = INT32_MAX; for (uint32_t i = 0; i < pts.size(); i++) { for (uint32_t j = 0; j < pts[i].size(); j++) { int dis = bfs(pt, pts[i][j]); if (minval > dis) { minval = dis; idx.clear(), p.clear(); idx.push_back(i), p.push_back(j); } else if (minval == dis) { idx.push_back(i), p.push_back(j); } } } return minval; } vector<point> getMinPoints(point pt, vector<vector<point>> pts) { vector<point> res; int idx, p; for (uint32_t i = 0; i < pts.size(); i++) { int minval = INT32_MAX; for (uint32_t j = 0; j < pts[i].size(); j++) { int dis = bfs(pt, pts[i][j]); if (minval > dis) { minval = dis; idx = i, p = j; } } res.push_back(pts[idx][p]); } return res; } // 贪心法+bfs搜索计算最小路径 int getMinPath(point bp, point ep, vector<vector<point>> points) { int sum = 0, minSum = INT32_MAX; vector<int> idx, p; vector<point> ap; vector<vector<point>> apt; point pt; ap = getMinPoints(bp, points); // 获取与bp点距离最近的所有点 for (int x = 0; x < ap.size(); x++) { pt = bp; sum = bfs(pt, ap[x]); apt = points; apt.erase(apt.begin() + x); pt = ap[x]; // 设置为当前点 if (apt.size() > 0) { sum += getMinBfs(pt, idx, p, apt); while (1) { if (idx.size() > 1) { // 有多个并列最近点的情况 int tmin = INT32_MAX, ts, k; for (int i = 0; i < idx.size(); i++) { vector<vector<point>> tp = apt; tp.erase(tp.begin() + idx[i]); ts = getMinPath(apt[idx[i]][p[i]], ep, tp); // 计算以并列点为起点的路径 if (tmin > ts) { tmin = ts; k = i; } // 记录最小路径 } idx[0] = idx[k], p[0] = p[k]; // 更新最小路径 } pt = apt[idx[0]][p[0]]; apt.erase(apt.begin() + idx[0]); if (apt.size() == 0) break; sum += getMinBfs(pt, idx, p, apt); } } sum += bfs(pt, ep); // 加上到出口点的距离 if (minSum > sum) minSum = sum; } return minSum; } int main() { cin >> n >> m; for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) { cin >> d[i][j]; if (d[i][j] != '#' && d[i][j] != '.') { base.push_back(item(point(i, j), d[i][j])); } if (d[i][j] == 'I') bp = point(i, j); if (d[i][j] == 'O') ep = point(i, j); } // 扩展点,增加同方向的 for (int i = 0; i < base.size(); i++) { vector<point> vp; if (base[i].c != 'I' && base[i].c != 'O') { vp = getpoints(base[i].c, base[i].pt); pts.push_back(vp); } } int sum1 = getMinPath(bp, ep, pts); // 正向计算 int sum2 = getMinPath(ep, bp, pts); // 反向计算 cout << (sum1 > sum2 ? sum2 : sum1) << endl; // 取最小值 return 0; }
上一题 下一题