2014北京网络赛09题,hdu 5040
这次网络赛真是惨,也怪做题策略没想好,当时切完签到题之类的水题之后,马上就去看06青蛙那题去了。结果被那只死青蛙给坑惨了T_T。。。搞了四小时没搞出来...跪给那只青蛙了。。。本来当时是准备要做这道题的,题目描述也是好蛋疼,有人说这题不如直接去看Clarification,不看题目了,这也说明这题题目描述确实不清晰,虽然没这么夸张,题目还是得看的。
重新看这道题,不是很难,最短时间的话,那当然想到BFS,纯BFS的话,只是最短步数,所以我们需要+优先队列。状态的话,只需要坐标(x,y)还有时间cur_t%4这三个元素就行了。
解释一下为什么是cur_t%4,仔细想想会发现,这一题每个状态之间的不同点,除了当前位置的坐标,还有所有监视器的转向,而这个转向是以4为周期的没错吧,所以,只要某两个状态的坐标相同,且t%4也相同的话,那么这就是一个状态,压进队列一次就不用再压第二次了。除了这一点,其他应该没什么难点。后来写了一份代码,一炮就过了。。T_T为什么当时没先做这个?
代码:
#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#define N 511
using namespace std;
int n,dir[4][2]={{0,-1},{-1,0},{0,1},{1,0}};//E==0,S==1,W==2,N==3
int change[110];
bool vis[N][N][5];
char a[N][N];
struct node
{
int x,y,t;
node(){;} //构造函数
node(int xx,int yy,int tt){x=xx,y=yy,t=tt;}//构造函数
bool operator<(const node s)const{return t>s.t;}
};
int check(int x,int y,int t)//return 1代表该位置当前被灯照到,2代表当前位置没有灯照射,也可以走,0代表不可达
{
if(x<1||x>n||y<1||y>n||a[x][y]=='#') return 0;
if(change[a[x][y]]!=-1) return 1;
for(int i=0;i<4;i++)//要知道当前点有没有被照到,需要查看当前点四个方向上有没有灯朝向这个点
{
int xx=x+dir[i][0],yy=y+dir[i][1];
if(xx<1||xx>n||yy<1||yy>n) continue;
int tmp=change[a[xx][yy]];//tmp>=0代表当前点有灯
if(tmp>=0&&(tmp+t)%4==i) return 1;
//(tmp+t)代表当前时间,%4代表此时灯的转向,稍微设计了一下方向函数dir,使得(tmp+t)==i的时候,说明该点被照到
}
return 2;
}
int bfs(int sx,int sy)
{
memset(vis,0,sizeof(vis));
priority_queue<node> que;
que.push(node(sx,sy,0));
while(!que.empty())
{
node tmp=que.top();que.pop();
if(a[tmp.x][tmp.y]=='T') return tmp.t;
int cur_t;
//不移动的情况
cur_t=tmp.t+1;
if(!vis[tmp.x][tmp.y][cur_t%4]) vis[tmp.x][tmp.y][cur_t%4]=1,que.push(node(tmp.x,tmp.y,cur_t));
int flag=check(tmp.x,tmp.y,tmp.t);//flag=1说明当前点被照亮
for(int i=0;i<4;i++)
{
int cx=tmp.x+dir[i][0],cy=tmp.y+dir[i][1];
int che=check(cx,cy,tmp.t);
if(che==0) continue;
if(che==1||flag==1) cur_t=tmp.t+3;//要移动的点或者当前点被照亮
else if(che==2) cur_t=tmp.t+1;
if(!vis[cx][cy][cur_t%4])
vis[cx][cy][cur_t%4]=1,que.push(node(cx,cy,cur_t));
}
}
return -1;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("D:/in.txt","r",stdin);
#endif // ONLINE_JUDGE
memset(change,-1,sizeof(change));
change['E']=0,change['S']=1,change['W']=2,change['N']=3;
int T,cas=1;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%s",a[i]+1);
int sx,sy;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(a[i][j]=='M') sx=i,sy=j;
int ans=bfs(sx,sy);
printf("Case #%d: %d\n",cas++,ans);
}
return 0;
}