[USACO17DEC]Standing Out from the Herd——2019暑假篇

目录

一.题目

二.题解

三.Code

谢谢!


这道题看着就脑壳痛

一.题目

点击打开链接

二.题解

先分析一下这道题目:

当人在推箱子的时候,如果直接往人站的方向推,就直接判断前方是否是墙或出界;

但当人需要换个方向推箱子时,就需要判断人是否能到箱子的另一面,这就是本题的难点。

下面就来解决难点:

很明显,箱子堵住了人去到箱子另一面的一条路,人要通过另一条路过去,就是说人现在的位置和将要到达的位置要在一个点双连通分量内,对,没错,就是点双连通分量

好,来缕一下思路:

1.Tarjan处理处点双连通分量

2.预处理判断人是否能到箱子的四个方向

3.BFS搜索箱子能到的位置

4.输出答案

注意细节有太多!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!


我是用O2优化过的

三.Code

#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#include <stack>
#include <queue>
using namespace std;
#define M 1505
int n, m, q, a[M][M], sx, sy, tx, ty, dfn[M * M], low[M * M], cnt, cut;
char g;
int dir[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
bool vis[M][M], flag[M][M][5]; 
vector <int> G[M * M];
stack <int> s;
int id (int x, int y){
	return m * (x - 1) + y;
}
struct node {
	int xx, yy, d;
	node (){};
	node (int X, int Y, int D){
		xx = X;
		yy = Y;
		d = D;
	}
};
void Tarjan (int x, int y, int nx, int ny){//特别容易打错
	int v = id (x, y);
	dfn[v] = low[v] = ++ cnt;
	for (int i = 0; i < 4; i ++){
		int tox = x + dir[i][0];
		int toy = y + dir[i][1];
		if (a[tox][toy] || (tox == nx && toy == ny))
			continue;
		int u = id (tox, toy);
		if (! dfn[u]){
			s.push (u);
			Tarjan (tox, toy, x, y);
			low[v] = min (low[u], low[v]);
			if (dfn[v] <= low[u]){
				cut ++;
				int k = 0;
				while (k != u){
					k = s.top ();
					s.pop ();
					G[k].push_back (cut);
				}
				G[u].push_back (cut);
				G[v].push_back (cut);
			}
		}
		else if (tox != nx || toy != ny)
				low[v] = min (dfn[u], low[v]);
	}
}
void prepare (){
	queue <node> Q;
	Q.push (node (sx, sy, 0));
	vis[sx][sy] = 1;
	while (! Q.empty ()){
		node f = Q.front ();
		Q.pop ();
		for (int i = 0; i < 4; i ++){
			int tox = f.xx + dir[i][0];
			int toy = f.yy + dir[i][1];
			if (a[tox][toy] || (tox == tx && toy == ty) || vis[tox][toy])
				continue;
			Q.push (node (tox, toy, 0));
			vis[tox][toy] = 1;
		}
	}
}
bool check (int x, int y){
	for (int i = 0; i < G[x].size (); i ++){
		for (int j = 0; j < G[y].size (); j ++){
			if (G[x][i] == G[y][j])
				return 1;
		}
	}
	return 0;
}
void BFS (){
	queue <node> Q;
	for (int i = 0; i < 4; i ++){
		if (vis[tx - dir[i][0]][ty - dir[i][1]]){//一定要减,人在箱子前进方向的反面
			Q.push (node (tx, ty, i));
			flag[tx][ty][i] = 1;
		}
	}
	while (! Q.empty ()){
		node f = Q.front ();
		Q.pop ();
		int tox = f.xx + dir[f.d][0];
		int toy = f.yy + dir[f.d][1];
		if (! a[tox][toy]){
			Q.push (node (tox, toy, f.d));
			flag[tox][toy][f.d] = 1;
		}
		for (int i = 0; i < 4; i ++){
			tox = f.xx - dir[i][0];
			toy = f.yy - dir[i][1];
			if (a[tox][toy] || flag[f.xx][f.yy][i] || i == f.d)
				continue;
			int u = id (f.xx - dir[f.d][0], f.yy - dir[f.d][1]), v = id (tox, toy);
			if (check (u, v)){
				Q.push (node (f.xx, f.yy, i));
				flag[f.xx][f.yy][i] = 1;
			}
		}
	}
}
int main (){
	scanf ("%d %d %d", &n, &m, &q);
	for (int i = 1; i <= n; i ++){
		scanf ("\n");
		for (int j = 1; j <= m; j ++){
			scanf ("%c", &g);
			if (g == '.')
				a[i][j] = 0;
			if (g == '#')
				a[i][j] = 1;
			if (g == 'A')
				sx = i, sy = j, a[i][j] = 0;
			if (g == 'B')
				tx = i, ty = j, a[i][j] = 0;
		}
	}
	for (int i = 0; i <= n + 1; i ++)
		a[i][0] = a[i][m + 1] = 1;
	for (int i = 0; i <= m + 1; i ++)
		a[0][i] = a[n + 1][i] = 1;
	for (int i = 1; i <= n; i ++){
		for (int j = 1; j <= m; j ++){
			if (! dfn[id (i, j)] && ! a[i][j])
				Tarjan (i, j, 0, 0);
		}
	}
	prepare ();
	BFS ();
	while (q --){
		int x, y;
		scanf ("%d %d", &x, &y);
		if (flag[x][y][0] || flag[x][y][1] || flag[x][y][2] || flag[x][y][3] || (x == tx && y == ty))
			printf ("YES\n");
		else
			printf ("NO\n");
	}
	return 0;
}

谢谢!

发布了61 篇原创文章 · 获赞 32 · 访问量 8353

猜你喜欢

转载自blog.csdn.net/weixin_43908980/article/details/96178780