CF585B Phillip and Trains

题意:

给定一个 33nn 列的地图,地图中有一些火车。每列火车都是一个在任意一行且至少长两个格的一些连续方格。同一列火车用相同字母表示,空地表示为 .。现在有一个起点,字符表示为 s,每次 s 先向右走一格,然后可以选择向上向下或不变位置。之后每一列火车会向左行驶两格。问有没有方法使得从起点开始不被火车撞死到达任意一行最后一列。

解法:

这题用搜索解决。因为问题是连通性而非最小步数等问题,广搜深搜均可解决。但是特别要注意的地方是存储火车以及火车向左行驶两步的模拟。

我们考虑用一个结构体存储一列火车的信息,那么我们需要存储的是这列火车所在的行,火车最左端与最右端所在的列,总共 33 个信息。我是这样写的:

struct Node
{
	int l, r, x; // 左端点所在的列、右端点所在的列、火车所在的行
	Node(int a, int b, int c): l(a), r(b), x(c){} // 构造函数
	Node()
	{
		l = r = x = 0;
	} // 构造函数
};

处理字符串时我们可以用 vector 存储每列火车,用 unordered_map 记录每列火车是否以及存储,因为题面说相同的火车字符相同。

剩下的问题在于火车行驶的模拟,这里有一个细节,例如以下例子:

1
6 1
s...AA
....BB
....CC

那么其中一种方案的下一步是:

..AA..
.sBB..
..CC..

紧接着是:

AA....
BBs...
CC....

但是很明显最后这个状态无法实现,因为在 s 转移时会被火车撞到。但是如果直接模拟那么转移后其实是合法的,但是转移过程不合法。所以一定要对转移过程特判。

代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <string>
#include <cstring>
#include <utility>
#include <unordered_map>
#include <vector>
using namespace std;

const int N = 105;
string s[N];
int t, n, k;
bool f[N][N];

struct Node
{
	int l, r, x;
	Node(int a, int b, int c): l(a), r(b), x(c){}
	Node()
	{
		l = r = x = 0;
	}
};

vector<Node> train; // 保存火车
unordered_map<char, bool> mp;

inline bool check(int x, int y)
{
	for (int i = 0; i < train.size(); i++)
	{
		if (train[i].x == x && train[i].l <= y && train[i].r >= y)
		{
			return true;
		}
	}
	return false;
}

inline bool work_next(int x, int y)
{
	for (int i = 0; i < train.size(); i++)
	{
		if (train[i].x == x && train[i].l <= y && train[i].r >= y) return true;
		if (train[i].x == x && train[i].l - 2 <= y && train[i].r >= y) return true;
	}
	for (int i = 0; i < train.size(); i++)
	{
		train[i].l -= 2;
		train[i].r -= 2;
	}
	return false;
}

inline void work_pre()
{
	for (int i = 0; i < train.size(); i++)
	{
		train[i].l += 2;
		train[i].r += 2;
	}
}

inline bool dfs(int x, int y)
{
	if (x < 1 || x > 3 || y < 0 || y >= n || f[x][y] || check(x, y)) return false;
	f[x][y] = true;
	if (y == n - 1)
	{
		//cout << x << " " << y << endl;
		puts("YES");
		return true;
	}
	y++;
	if (check(x, y)) return false;
	if (!work_next(x, y))
	{
		if (dfs(x, y)) return true;
		work_pre();
	}
	if (!work_next(x - 1, y))
	{
		if (dfs(x - 1, y)) return true;
		work_pre();
	}
	if (!work_next(x + 1, y))
	{
		if (dfs(x + 1, y)) return true;
		work_pre();
	}
	return false;
}


int main()
{
	scanf("%d", &t);
	while (t--)
	{
		memset(f, false, sizeof(f));
		scanf("%d %d", &n, &k);
		train.clear();
		mp.clear();
		int sx = 0, sy = 0;
		for (int i = 1; i <= 3; i++)
		{
			cin >> s[i];
		}
		for (register int i = 1; i <= 3; i++)
		{
			for (register int j = 0; j < n; j++)
			{
				if (s[i][j] == 's')
				{
					sx = i;
					sy = j;
				}
				else
				{
					if (s[i][j] == '.' || mp.count(s[i][j])) continue;
					mp[s[i][j]] = true;
					Node p;
					p.x = i;
					p.l = j;
					p.r = j;
					for (register int k = j + 1; k < n; k++)
					{
						if (s[i][k] != s[i][j])
						{
							p.r = k - 1;
							break;
						}
					}
					train.push_back(p);
				}
			}
		}
		if (!dfs(sx, sy))
		{
			puts("NO");
		}
	}
	return 0;
}
posted @   HappyBobb  阅读(9)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示