【JZOJ 省选模拟】【USACO 2017 December Platinum】6644.Push a Box

题目

Description
Bessie and her friends have invented a new game. The game is named accurately, but not particularly creatively. They call it the “Push A Box Around The Barn To Get It In The Right Spot And Don’t Move The Hay” game (if you think that’s excessive, you should see some of the variable names the cows use when they write code…) The barn can be modeled as an N×M rectangular grid. Some of the grid cells have hay in them. Bessie occupies one cell in this grid, and a large wooden box occupies another cell. Bessie and the box are not able to fit in the same cell at the same time, and neither can fit into a cell containing hay.

Bessie can move in the 4 orthogonal directions (north, east, south, west) as long as she does not walk into hay. If she attempts to walk to the space with the box, then the box will be pushed one space in that direction, as long as there is an empty cell on the other side. If there is no empty cell, then Bessie will not be able to make that move.

A certain grid cell is designated as the goal. Bessie’s goal is to get the box into that location.

Given the layout of the barn, including the starting positions of the box and the cow, and the target position of the box, determine if it possible to win the game.

Note: This problem allows 512MB of memory usage, up from the default limit of 256MB.
一个谷仓是一个N*M的矩形网格,有一些网格里有干草。Bessie站在其中一个格子内,还有一个格子里有一个大木箱。Bessie不能和大木箱在一个格子里,也不能和干草在一个格子里。

如果她不与干草一个格子,她就可以往自己旁边的四个方向(东西南北)移动,如果她想移动到有木箱的格子里,那个木箱就会被她推一格(只要木箱的那个方向还有空间),如果没有空间,那Bessie就不能移动了。

给你谷仓的布局(空格子,干草以及木箱位置)以及Bessie的出发位置和箱子要被推到的位置,请你帮忙计算Bessie能不能把木箱推到指定位置。

Input
The first line has three numbers, N, M, and Q, where N is the number of rows in the grid and M is the number of columns.

1≤N,M≤1500.
1≤Q≤50,000.
On the next N lines is a representation of the grid, where characters represent empty cells (.), hay (#), Bessie’s starting position (A), and the box’s initial location (B).

This is followed by Q lines, each with a pair of integers (R,C). For each pair, you should determine if it is possible to get the box to that cell at row R, column C, starting from the initial state of the barn. The top row is row 1, and the left column is column 1.
第一行有3个数,N,M,Q,其中N是谷仓的行数,M是列数。

1≤N,M≤1500.

1≤Q≤50,000.

接下来N行是谷仓的初始布局,其中“.”代表空格子,“#”代表干草格子,“A”代表Bessie的初始位置,“B”是木箱的初始位置。

接下来Q行,每行一个座标(R,C),代表第R行第C行。对于每行,你要输出Bessie是否有可能把箱子推到这个位置。

Output
Q lines, each with either the string “YES” or “NO”.
Q行,每行一个答案,如果Bessie能走到,输出“YES”,否则输出“NO”。

Sample Input
5 5 4
##.##
##.##
A.B…
##.##
##.##
3 2
3 5
1 3
5 3

Sample Output
NO
YES
NO
NO

Data Constraint

思路

良心题
考虑记dp[i][j][0…3]为箱子在i,j,人在箱子的方向是否能够到达。
那么搜索的时候就有两种操作:向前推;转向;

向前推简单,但是转向就有说法。
我们发现,如果把箱子看成一个个点,那么与它处于一个双联通分量的一定可以到达

所以tarjan求点双预处理即可

代码

#include<cstdio>
#include<vector>
#include<stack>
#include<queue>
#include<cctype>
using namespace std;
const int N=1507;
const int dx[]={1,-1,0,0},dy[]={0,0,1,-1};
int sx,sy,tx,ty;
int p[N*N][5];
inline int read(){
    int x=0,f=1;char ch=getchar();
    while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
    return x*f;
}
struct E
{
	int to,next;
}e[N*N*4];
int ls[N*N],dfn[N*N],low[N*N],tot,cnt,total,a[N][N],d[N][N][4],b[N][N],n,m,q,id;
inline void add(int u,int v)
{
	e[++cnt].to=v; e[cnt].next=ls[u]; ls[u]=cnt;
}
stack<int> st;

inline void tarjan(int u)
{
	dfn[u]=low[u]=++tot;
	st.push(u);
	for(register int i=ls[u]; i; i=e[i].next)
	{
		int v=e[i].to;
		if(dfn[v]) low[u]=min(dfn[v],low[u]);
		else
		{
			tarjan(v);
			low[u]=min(low[v],low[u]);
			if(low[v]>=dfn[u])
			{
				total++;
				while(!st.empty())
				{
					int t=st.top(); st.pop();
//					p[t].push_back(total);
					p[t][++p[t][0]]=total;
					if(t==v) break;
				}
//				p[u].push_back(total);
				p[u][++p[u][0]]=total;
			}
		}
	}
}
inline bool check(int x1,int y1,int x2,int y2)
{
	int x=a[x1][y1],y=a[x2][y2];
	for(register int i=1; i<=p[x][0]; i++) for(register int j=1; j<=p[y][0]; j++) 
	{
//		printf("%d %d\n",p[x][i],p[y][j]);
		if(p[x][i]==p[y][j]) return 1;
	}
		
	return 0;
}
struct Q1
{
	int x,y;
};
struct Q2
{
	int x,y,t;
};
inline void solve(int X)
{
	queue<Q2> q;
	q.push((Q2){tx,ty,X}); d[tx][ty][X]=1;
	while(!q.empty())
	{
		int x=q.front().x,y=q.front().y,s=q.front().t;
		q.pop();
		for(register int i=0; i<4; i++) 
		{
			if(i==s) continue;
			int nx=x+dx[i],ny=y+dy[i];
			if(!a[nx][ny]||d[x][y][i]) continue;
			if(check(nx,ny,x+dx[s],y+dy[s])) d[x][y][i]=1,q.push((Q2){x,y,i});
		}
		int nx=x+dx[s^1],ny=y+dy[s^1];
		if(!a[nx][ny]||d[nx][ny][s]) continue;
		d[nx][ny][s]=1,q.push((Q2){nx,ny,s});
	}
}
inline void bfs()
{
	queue<Q1> q;
	q.push((Q1){sx,sy}); b[sx][sy]=1;
	while(!q.empty())
	{
		Q1 u=q.front(); q.pop();
		for(register int i=0; i<4; i++)
		{
			Q1 v=(Q1){u.x+dx[i],u.y+dy[i]};
			if(b[v.x][v.y]||!a[v.x][v.y]) continue;
			b[v.x][v.y]=1; q.push(v);
			if(v.x==tx&&v.y==ty) solve(i^1);
		}
	}
}
char s[N][N];
int main()
{
	freopen("pushabox.in","r",stdin); freopen("pushabox.out","w",stdout);
	n=read(); m=read(); q=read();
	for(register int i=1; i<=n; i++) scanf("%s",s[i]+1),s[i][0]='#',s[i][m+1]='#';
	for(register int i=1; i<=m; i++) s[0][i]='#',s[n+1][i]='#';
	for(register int i=1; i<=n; i++) for(register int j=1; j<=m; j++)
	{
		if(s[i][j]!='#') a[i][j]=++id;
		if(s[i][j]=='A') sx=i,sy=j;
		if(s[i][j]=='B') tx=i,ty=j;
	}
	for(register int i=1; i<=n; i++) for(register int j=1; j<=m; j++) if(a[i][j]) for(register int k=0; k<4; k++)
		if(a[i+dx[k]][j+dy[k]]) add(a[i][j],a[i+dx[k]][j+dy[k]]);
	for(register int i=1; i<=n; i++) for(register int j=1; j<=m; j++) if(a[i][j]&&!dfn[a[i][j]]) tarjan(a[i][j]);
	bfs();
	while(q--)
	{
		int x=read(),y=read(),yjy=0;
//		scanf("%d%d",&x,&y);
		for(register int i=0; i<4; i++) yjy|=d[x][y][i];
		if(yjy==1||(x==tx&&y==ty)) puts("YES");else puts("NO");
	}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章