首页 > 代码库 > hdu 5040 Instrusive【BFS+优先队列】

hdu 5040 Instrusive【BFS+优先队列】

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;
}


hdu 5040 Instrusive【BFS+优先队列】