题目大意:有一个m*n大小的房间与房间的描述,(x,y)=1代表该点不可通过或到达,(x,y)=0代表该点能通过或到达。然后给你若干个行动的描述,每一步按先后顺序排列,包含的参数有移动的最短距离,最长距离与方向。问房间有几个可能的起点,使其能够走完全部行动。
思路:令step[i]为第i步行动,dp[k][i][j]代表在第k步时从房间(i,j)为起点开始行动,能否走完剩下的行动。若能则赋为1,反之为0;则有递推关系dp[k-1][i][j]=1,如果dp[k][i+step[k]][j+step[k]]=1,反之为0。从后到前反推,最后dp[0][i][j]中1的个数即为可能的起点数。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
struct Step
{
int min_step,max_step;
int direction;
}step[5005];
bool dp1[105][105],dp2[105][105];
int map[105][105];
int dx[]={-1,1,0,0};
int dy[]={0,0,-1,1};
int main(int argc, char** argv)
{
int t,m,n,i,j,k,left,right,step_num,cnt,xx,yy,ans;
char orientation;
scanf("%d",&t);
while (t--)
{
scanf("%d%d",&m,&n);
for (i=1;i<=m;i++)
for (j=1;j<=n;j++)
scanf("%d",&map[i][j]);
for (i=0;i<=m+1;i++)
map[i][0]=map[i][n+1]=1;
for (j=0;j<=n+1;j++)
map[0][j]=map[m+1][j]=1;
step_num=0;
while (scanf("%d%d",&left,&right)==2 && left!=0 && right!=0)
{
scanf(" %c",&orientation);
step_num++;
step[step_num].min_step=left;
step[step_num].max_step=right;
if (orientation=='R')
step[step_num].direction=2;
else if (orientation=='L')
step[step_num].direction=3;
else if (orientation=='U')
step[step_num].direction=1;
else
step[step_num].direction=0;
}
memset(dp2,false,sizeof(dp2));
for (i=1;i<=m;i++)
for (j=1;j<=n;j++)
if (map[i][j]==0)
dp2[i][j]=true;
for (k=step_num;k>=1;k--)
{
memset(dp1,false,sizeof(dp1));
for (i=1;i<=m;i++)
for (j=1;j<=n;j++)
if (dp2[i][j])
{
xx=i;
yy=j;
for (cnt=1;cnt<step[k].min_step;cnt++)
{
xx+=dx[step[k].direction];
yy+=dy[step[k].direction];
if (map[xx][yy]==1)
break;
}
if (cnt>=step[k].min_step)
for (cnt=step[k].min_step;cnt<=step[k].max_step;cnt++)
{
xx+=dx[step[k].direction];
yy+=dy[step[k].direction];
if (map[xx][yy]==0)
dp1[xx][yy]=true;
else
break;
}
}
memcpy(dp2,dp1,sizeof(dp1));
}
ans=0;
for (i=1;i<=m;i++)
for (j=1;j<=n;j++)
if (dp1[i][j])
ans++;
printf("%d\n",ans);
}
return 0;
}