这段时间要沉迷刷题一段时间了,就让优快云陪我一起吧!
一、题目大意
博格是一个非常强大的种族,它来自银河系的三角洲象限。博格集体是用来描述博格文明群体意识的术语。每个博格人都通过复杂的子空间网络与集体联系,确保每个成员得到持续的监督和指导。
你的任务是帮助博格通过开发一个程序,帮助博格估计扫描迷宫的最低成本,以吸收隐藏在迷宫中的外星人,通过向上下左右移动。棘手的是,搜索的开始是由100多个人组成的。每当外星人被同化时,或者在搜索开始时,该群体可能会分成两组或更多组(但他们的意识仍然是集体的)。搜索迷宫的成本被定义为搜索中涉及的所有组所覆盖的总距离。也就是说,如果原始组走五步,则分成两组,每组步行三步,总距离为11 = 5 + 3 + 3。
题目输入的第一行,是一个整数N,代表测试样例数。每个测试样例的第一行是两个整数M,N,表示地图为NM (注意,不是我写反了,就是这样的!!).然后接下来就是NM的地图,其中’ '表示开放区域,'A’表示外星人,‘S’表示搜索开始的地方,’#'表示墙。
对于每个测试用例,输出一行包含成功搜索迷宫的最低成本,不留外星人。
二、题目思路以及AC代码
兄弟,看到这,我只能说你赚到了。一会你就知道我为什么这么说了,因为这道题的坑,我可以说几乎踩了个遍(哭死)。
首先,看到这道题,第一反应是bfs的题,但又仔细一看,不对!会分叉!然后再进行分析,发现其实分叉的目的就是要覆盖所有的可能路径,然后找一条最小的,这也就是最小生成树问题了,思路很明确,以为20分钟就可以写出来。呵,下面就是我的踩坑时间。
由于是最小生成树,就要明确顶点和边的权值,在本题中,顶点就是图中’S’和’A’的位置,而边自然就是他们相互之间需要达到的距离了(这里用bfs求解)。好了,思路明确那就写吧!
第一遍,很快bfs和Prim全部写完,提交!TLE,好吧,看来不能那么简单的bfs,那就优化一下,在O(n)的复杂度内求解(i, j)到所有顶点的距离,这样应该就可以了吧!
第二遍,又没过多长时间,新版bfs求出来了,提交!WA,终于不是TLE了,还有些许欣慰,WA嘛,我自以为思路又没错,肯定是爆int了吧,也没怎么仔细考虑,一想MST确实可能爆int,那就改吧!
第三遍,这就很快了,改int为LL,提交!还是WA?思路错了吗,没有啊,又琢磨了好长时间无果之后,我决定去寻求帮助,去看了一下discuss,发现了一个问题。
好了,这么明显也不需要我多说什么了,匿了。
下面给出AC代码:
bfs + Prim:
#include <iostream>
#include <queue>
#include <vector>
#define INF 10000000
#define MAXN 55
using namespace std;
struct Point {
int x, y;
Point(int a, int b) {
x = a;
y = b;
}
};
typedef long long ll;
typedef pair<Point, ll> pp;
int dx[4] = { 0, 0, -1, 1 };
int dy[4] = { -1, 1, 0, 0 };
int flag[MAXN][MAXN]; // the identifier of node
char map[MAXN][MAXN]; // start from (1, 1)
int N, M; // map is N * M Matrix
bool vis[MAXN][MAXN];
// For Prim
ll edges[110][110];
ll dist[110];
bool visited[110];
void init() {
for (int i = 0; i < MAXN; i++) {
for (int j = 0; j < MAXN; j++) {
flag[i][j] = 0;
vis[i][j] = false;
map[i][j] = '\0';
}
}
for (int i = 0; i < 110; i++) {
for (int j = 0; j < 110; j++) {
if (i == j) edges[i][j] = 0;
else edges[i][j] = INF;
}
dist[i] = INF;
visited[i] = false;
}
}
void bfs(int sx, int sy) {
// initialization
for (int i = 0; i < MAXN; i++) {
for (int j = 0; j < MAXN; j++) {
vis[i][j] = false;
}
}
queue<pp> q;
while (!q.empty())q.pop();
Point start(sx, sy);
q.push(make_pair(start, 0));
vis[sx][sy] = true;
while (!q.empty()) {
pp p = q.front(); q.pop();
int xx = p.first.x;
int yy = p.first.y;
ll pace = p.second;
if (flag[xx][yy]) {
int u = flag[sx][sy];
int v = flag[xx][yy];
edges[u][v] = edges[v][u] = pace;
}
for (int i = 0; i < 4; i++) {
int nx = xx + dx[i];
int ny = yy + dy[i];
if (vis[nx][ny]) continue;
if (nx <= 0 || nx > N || ny <= 0 || ny > M || map[nx][ny] == '#') continue;
vis[nx][ny] = true;
q.push(make_pair(Point(nx, ny), pace + 1));
}
}
}
ll Prim(int num) {
// initialization
for (int i = 0; i < 110; i++) {
dist[i] = INF;
visited[i] = false;
}
ll ans = 0;
dist[1] = 0;
for (int i = 1; i <= num; i++) {
ll min = INF;
int x = -1;
for (int j = 1; j <= num; j++) {
if (!visited[j] && dist[j] < min) {
min = dist[x = j];
}
}
if (x == -1) break;
visited[x] = true;
ans += min;
for (int j = 1; j <= num; j++) {
if (!visited[j] && dist[j] > edges[x][j]) {
dist[j] = edges[x][j];
}
}
}
return ans;
}
int main()
{
int T;
scanf("%d", &T); // T <= 50
while (T--) {
init();
scanf("%d%d", &M, &N); // N * M N, M <= 50
char c;
while ((c = getchar()) != '\n') {
}
int sx, sy;
int idx = 1; // idx <= 100
for (int i = 1; i <= N; i++) { // start from (1, 1)
for (int j = 1; j <= M; j++) {
map[i][j] = getchar();
if (map[i][j] == 'S' || map[i][j] == 'A') {
flag[i][j] = idx++;
}
}
getchar();
}
int size = 0; // size <= 100, same as idx
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= M; j++) {
if (flag[i][j]) {
bfs(i, j);
size++;
}
}
}
printf("%lld\n", Prim(size));
}
return 0;
}