1 条题解

  • 0
    @ 2025-8-24 22:05:31

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar liangbowen
    不能再摆了,,,

    搬运于2025-08-24 22:05:31,当前版本为作者最后更新于2022-06-05 08:47:30,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    前言

    题目传送门!

    或许更好的阅读体验?

    这题算是一道中模拟?

    码量不会很高,大概只有 100100150150 行。

    思路

    1. 输入地图。

      注意,还不能读入蛇的行动指令,因为我们不知道有几条蛇

    2. 使用广搜得出每条蛇的信息。

      这个就是搜连通块,惟一不同的是,要使用队列存下这条蛇。

    3. 写一个死亡函数,处理蛇死亡后的信息。

      这个并不困难,只要将队列清空,顺便将整条蛇蛇变成食物

    4. 写移动函数,这里要分几种情况考虑。

      • 移动后撞上墙,死掉。

      • 移动后撞上身体(当然也包括头),死掉。

        此处的『撞上身体』既包括别人的身体,也包括自己的身体。

      • 移动后有食物。

        我们可以让其他部位保持不动,蛇头向食物处扩充一格。

      • 移动后,什么都没有,是平地。

        我们可以做两件事达到效果:

        首先扩充蛇头。

        然后消除蛇尾。

        用普通的队列难以达到这种效果,因此可以使用双端队列

    5. 读入蛇的行动指令,并移动。

    6. 最后输出。

      由于题目让我们按顺序输出,所以我们需要排序。

      然后还要再扫一遍地图,记录食物数量。

    坑点

    这些坑点指,题目并没有说清楚的地方,更多细节请查看代码。

    1. 很多人都有疑问,为什么可以直接搜连通块分辨每条蛇。

      很多人都忽略了一个细节,题目保证了:

      图中的蛇不会引起混淆(对于任意蛇头,最多只有一块蛇身于其相连,而蛇身最多为二连块)。

      因此,直接搜连通块是可行的。

    2. 蛇的移动顺序。

      蛇是按照回合制移动的,每一回合,编号小的蛇优先行动。

    完整代码

    #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); 
    }
    
    • 1

    信息

    ID
    3873
    时间
    1000ms
    内存
    125MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者