P4944 题解
作者:互联网
前言
这题算是一道中模拟?
码量不会很高,大概只有 \(100\) 至 \(150\) 行。
思路
-
输入地图。
注意,还不能读入蛇的行动指令,因为我们不知道有几条蛇。
-
使用广搜得出每条蛇的信息。
这个就是搜连通块,惟一不同的是,要使用队列存下这条蛇。
-
写一个死亡函数,处理蛇死亡后的信息。
这个并不困难,只要将队列清空,顺便将整条蛇蛇变成食物。
-
写移动函数,这里要分几种情况考虑。
-
移动后撞上墙,死掉。
-
移动后撞上身体(当然也包括头),死掉。
此处的『撞上身体』既包括别人的身体,也包括自己的身体。
-
移动后有食物。
我们可以让其他部位保持不动,蛇头向食物处扩充一格。
-
移动后,什么都没有,是平地。
我们可以做两件事达到效果:
首先扩充蛇头。
然后消除蛇尾。
用普通的队列难以达到这种效果,因此可以使用双端队列。
-
-
读入蛇的行动指令,并移动。
-
最后输出。
由于题目让我们按顺序输出,所以我们需要排序。
然后还要再扫一遍地图,记录食物数量。
坑点
这些坑点指,题目并没有说清楚的地方,更多细节请查看代码。
-
很多人都有疑问,为什么可以直接搜连通块分辨每条蛇。
很多人都忽略了一个细节,题目保证了:
图中的蛇不会引起混淆(对于任意蛇头,最多只有一块蛇身于其相连,而蛇身最多为二连块)。
因此,直接搜连通块是可行的。
-
蛇的移动顺序。
蛇是按照回合制移动的,每一回合,编号小的蛇优先行动。
完整代码
#include <iostream>
#include <cstdio>
#include <queue> //包含 queue 与 deque 两种数据类型。
#include <algorithm> //用于 sort 排序。
#define N 205
#define C 25
using namespace std;
int n, m, k;
int cur; //表示蛇的数量。
char a[N][N]; //表示地图。
int who[N][N]; //表示当前格子属于那一条蛇。
//后来发现这个 who 数组完全没使用到,所以不写也行。
string order[C]; //代表蛇的行动指令。
struct node
{
int x, y;
};
deque <node> snake[C]; //模拟当前的蛇。
void Input1(); //输入地图,不解释。
void bfs(); //搜索得出蛇的位置。
void debug(); //调试工具。
void die(int id); //第 id 条蛇死亡了。
void move(int id, char op); //对第 id 条蛇执行 op 指令。
void Input2(); //输入蛇的运行指令,但顺便利用 move() 函数移动处理。
void Output(); //输出答案。
int main()
{
Input1();
bfs();
//debug();
Input2();
//debug();
Output();
return 0;
}
void Input1() //实际输入只能输入一部分,因为必须 bfs 得出蛇的数量后,再输入指令。
{
scanf("%d%d%d", &n, &m, &k);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
cin >> a[i][j];
}
int dict[5][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
void bfs() //爆搜,没什么技巧。
{
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
if (a[i][j] == '@')
{
cur++;
queue <node> Q;
Q.push( (node){i, j} );
while (!Q.empty())
{
int x = Q.front().x, y = Q.front().y;
who[x][y] = cur;
snake[cur].push_back( (node){x, y} );
Q.pop();
for (int i = 0; i <= 3; i++)
{
int dx = x + dict[i][0], dy = y + dict[i][1];
if (dx < 1 || dx > n || dy < 1 || dy > m) continue;
if (who[dx][dy] == cur) continue;
if (a[dx][dy] == '#') Q.push( (node){dx, dy} );
}
}
}
}
void debug()
{
for (int i = 1; i <= cur; i++)
{
printf("\ni = %d:\n", i);
deque <node> Q = snake[i];
while (!Q.empty())
{
printf("(%d %d) ", Q.front().x, Q.front().y);
Q.pop_front();
}
}
}
void die(int id)
{
while (!snake[id].empty())
{
int x = snake[id].front().x, y = snake[id].front().y;
who[x][y] = 0; //消除标记。
a[x][y] = '&'; //变成食物。
snake[id].pop_front(); //把蛇给消除。
}
}
void move(int id, char op)
{
int x = snake[id].front().x, y = snake[id].front().y;
if (op == 'W') x--; //往上。
if (op == 'S') x++; //往下。
if (op == 'A') y--; //往左。
if (op == 'D') y++; //往右。
if (x < 1 || x > n || y < 1 || y > m) //撞边界上了,死亡。
{
die(id);
return;
}
if (a[x][y] == '#' || a[x][y] == '@') //撞身体上了,死亡。
{
die(id);
return;
}
int head_x = snake[id].front().x, head_y = snake[id].front().y; //原先的蛇头。
int tail_x = snake[id].back().x, tail_y = snake[id].back().y; //原先的蛇尾。
if (a[x][y] == '&') //吃到食物,直接扩充蛇。
{
snake[id].push_front( (node){x, y} );
a[x][y] = '@'; //食物处变成蛇头。
a[head_x][head_y] = '#'; //曾经的蛇头变成蛇身。
who[x][y] = id; //标记蛇。
}
if (a[x][y] == '.') //是平路,蛇头扩充,蛇尾消除。
{
//蛇头扩充。
snake[id].push_front( (node){x, y} );
a[x][y] = '@';
a[head_x][head_y] = '#';
who[x][y] = id;
//蛇尾消除。
snake[id].pop_back();
a[tail_x][tail_y] = '.';
who[tail_x][tail_y] = 0;
}
}
void Input2()
{
for (int i = 1; i <= cur; i++) cin >> order[i];
for (int j = 0; j < k; j++)
for (int i = 1; i <= cur; i++)
if (!snake[i].empty()) //需要注意,只有蛇没有死亡,才可以移动。
move(i, order[i][j]);
}
struct Snake
//存储每条蛇的信息。
{
int len, id;
}p[C];
bool cmp(Snake x, Snake y)
{
if (x.len != y.len) return x.len > y.len;
return x.id < y.id;
}
void Output()
{
//计算每条蛇的信息。
for (int i = 1; i <= cur; i++)
{
p[i].id = i;
deque <node> Q = snake[i];
while (!Q.empty())
{
p[i].len++;
Q.pop_back();
}
}
sort(p+1, p+cur+1, cmp); //按题目所述排序。
for (int i = 1; i <= cur; i++) printf("%d %d\n", p[i].len, p[i].id);
//计算食物数量并输出。
int cnt = 0;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
if (a[i][j] == '&')
cnt++;
printf("%d", cnt);
}
首发:2022-06-05 08:47:30
标签:int,题解,void,who,P4944,snake,front,id 来源: https://www.cnblogs.com/liangbowen/p/16622881.html