【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");
	}
}

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