CodeForces Gym 100971J 感觉题意有问题 BFS

本文解析了一道关于机器人位置交换的迷之AC代码问题。讨论了两种情况:存在T字型路口和路径数量大于等于2时的解决方案,并分享了两段AC代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

为了纪念这道题,我决定贴一个特别迷的AC代码上来,纪念我那估计二十来发WA和TLE。如果有人发现我的问题了,欢迎回复或者私信,感激不尽

链接:http://codeforces.com/gym/100971/problem/J

首先这道题的意思就是, 给一个地图,#表示障碍,.表示可以走,1表示1号机器人的位置,2表示2号机器人的位置,现在想交换两个人的位置,问能否做到,

两个限制条件就是,1:在同一时刻,他们不能在同一位置,2:如果他们相邻,那他们不能直接交换位置。


然后,我的理解,首先,他没有要求两个人必须同时走,就是有人可以等,那就简单很多了,分两种情况,一种是有T字型路口的,只要两个人之间有道路通过,那么有一个 就可以躲在T字型的一端,然后让另一个人先走,然后它在走,就可以,当然这个T字型路口必须是两个人可以走到的地方。第二种情况就是没有T字型路口,就是每个点周围四个可走的点都<=2,但是有1号的点和2号的点可以连成一个环,就是有回路,然后就肯定一个人从这条路走,一个人从另一条路走,就可以了

想想假如A和B之间只有一条路可走,而且这条路中间没有分叉,B在另一端有个T字型的点,那它可以先跑到T字型的一端躲起来,然后A走过了跑到T字型的另一端躲起来,然后B去A的位置,然后A再去B的位置,就完成交换了。

假如两人本来就相邻的话, 那如果路径数>=2,那也一个人从另一条路走,然后另一个人直接走过来就可以。假如是只能直接过去但是有T字型口的话,比如T字型点在A那里,A可以先躲到T字型的一端,B躲到另一端,A走到B的位置,B走到A的位置,也就完成了

想不出还有什么特殊情况,可能是我对题意理解有错?看他们的程序,好像只判有T字型点或者路径数>=2就行,难道题目保证AB是连通的?

所以,我就只说DFS的写法,在vj上也看到有人BFS写的,没去细看。

DFS,我觉得,

首先,判断嘛,假如路径数>=2,那么要么就是回路,成环,否则的话,肯定有T字型的点,然后就可以了,反正肯定是YES,

否则的话,就是如果(路径数==1,而且在他们可达的地方有T字型的点),就是YES,否则, 就是NO。

但是,这样就一直T,,简直没救了,,附上我的一份我认为对但是一直TLE on 20的代码,而且我感觉,好像没法再优化复杂度了吧,我是用的DFS跑路径数而且遍历所以可达点的,曾试过一次DFS跑路径数,BFS遍历所有点,也TLE on 20了。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <queue>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <set>
using namespace std;
#define ll long long
#define maxn 400005
const int dx[4] = { 0, 0, 1, -1 };
const int dy[4] = { 1, -1, 0, 0 };
int N, M;
char grid[maxn];
bool walk[maxn];
bool vis[maxn];
bool extra = false;
int ax, ay, bx, by;
int tmp;
int sum = 0;
int xx, yy;
void DFS(int x, int y,bool arrive)
{
	if (sum >= 2 || (sum == 1 && extra))
		return;
	if (extra == false && vis[x*M + y] == false)
	{
		vis[x*M + y] = true;
		tmp = 0;
		for (int i = 0; i < 4; ++i)
		{
			xx = x + dx[i];
			yy = y + dy[i];
			if (xx >= 0 && xx < N&&yy >= 0 && yy < M&&grid[xx*M + yy] != '#')
			{
				++tmp;
			}
		}
		if (tmp > 2)
			extra = true;
	}
	if (arrive)
	{
		for (int i = 0; i < 4; ++i)
		{
			xx = x + dx[i];
			yy = y + dy[i];
			if (xx >= 0 && xx < N&&yy >= 0 && yy < M&&grid[xx*M + yy] != '#'&&vis[xx*M + yy] == false)
			{
				//printf("%d %d\n", xx, yy);
				DFS(xx, yy, true);
			}
		}
	}
	else
	{
		bool flag = false;
		if (x == bx&&y == by)
		{
			++sum;
			flag = true;
		}
		walk[x*M + y] = true;
		for (int i = 0; i < 4; ++i)
		{
			xx = x + dx[i];
			yy = y + dy[i];
			if (xx >= 0 && xx < N&&yy >= 0 && yy < M&&grid[xx*M + yy] != '#'&&walk[xx*M + yy] == false)
			{
				//printf("%d %d\n", xx, yy);
				DFS(xx, yy, flag);
			}
		}
		walk[x*M + y] = false;
	}
}
int main()
{
	//freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
	scanf("%d%d", &N, &M);
	for (int i = 0; i < N; ++i)
	{
		scanf("%s", &grid[i*M]);
		for (int j = 0; j < M; ++j)
		{
			if (grid[i*M + j] == '1')
			{
				ax = i; ay = j;
				grid[i*M + j] = '.';
			}
			else if (grid[i*M + j] == '2')
			{
				bx = i; by = j;
				grid[i*M + j] = '.';
			}
		}
	}
	DFS(ax, ay,false);
	if (sum >= 2 || (sum == 1 && extra))
		printf("YES\n");
	else
		printf("NO\n");
	//system("pause");
	//while (1);
	return 0;
}

我不知道那个20是一组怎样的神数据,反正我把代码中的(sum == 1&&extra)都换成extra之后,就迷之AC了,,而且46ms,快的飞起,难道说只有有T字型的点就可以吗?假如从A出发有T字型的点,但是A和B直接不连通,那怎么做到交换两个人位置呢,被这题干了好久了,,,唉,又读了一遍题,也没发现问题啊。。。


然后附上一份别人的AC代码,我感觉是,迷之AC,这也能AC?没懂那个flag是什么意义
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
using namespace std;
#define maxn 200005
int main()
{
	//freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
	ios_base::sync_with_stdio(NULL);
	cin.tie(NULL); cout.tie(NULL);
	int N, M;
	cin >> N >> M;
	int cnt = 0;
	bool flag = true;
	vector<string> a(N);
	for (int i = 0; i < N; ++i)
	{
		cin >> a[i];
	}
	for (int i = 0; i < N; ++i)
	{
		for (int j = 0; j < M; ++j)
		{
			if (a[i][j] == '#')
				continue;
			cnt = 0;
			if (i != 0 && a[i - 1][j] != '#')
				++cnt;
			if (i != N - 1 && a[i + 1][j] != '#')
				++cnt;
			if (j != 0 && a[i][j - 1] != '#')
				++cnt;
			if (j != M - 1 && a[i][j + 1] != '#')
				++cnt;
			if (cnt >= 3)
			{
				cout << "YES" << endl;
				return 0;
			}
			if (cnt == 1)
				flag = false;
		}
	}
	if (flag)
		cout << "YES" << endl;
	else
		cout << "NO" << endl;
	//system("pause");
	//while (1);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值