hdu 5040 Instrusive (bfs)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5040

题意:给出一个棋盘图,给出起点,终点,和守卫的位置,每个守卫有东南西北的初始朝向,每个守卫的防守范围是两格(自身所在区域算一个),每过1秒钟,所有守卫的所朝方向都会顺时针旋转90度,从被监视位置到其他的任何位置都需要消耗3秒钟,从其他位置进入被监视位置需要3秒钟,其他的情况消耗1秒钟,当处于被监视位置时也可以停留若干秒,等处于非监视状态再继续,问从起点到终点的最短时间。

思路:

基本思路bfs,然后根据根据时间%4的结果,将图分成四份,每次从当前点进行扩展时,先判断当前所在点的状态是否被监视,据从再扩展到其他状态,如果处于被监视的状态,再分出一个原地不动的状态。

感觉这道题目就是要成分理解题意,然后代码敲的稳一点,姿势好一点就能A掉了。

code:

//hdu 5040 (bfs~)

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#define INF 1e9

using namespace std;

const int maxn=550;

struct ppp
{
    int x,y,ti;

    bool operator < (const ppp&a) const{
        return ti>a.ti;
    }
};
char cc[maxn][maxn];
int vis[maxn][maxn][4],N;
int dir[4][2]={{-1,0},{0,1},{1,0},{0,-1}};    //up down left right

bool judge(int x,int y)
{
    if(x<0||y<0||x>=N||y>=N) return false;
    if(cc[x][y]=='#') return false;
    return true;
}

int cal(int x,int y,int time)
{
    if(cc[x][y]=='N'||cc[x][y]=='S'||cc[x][y]=='E'||cc[x][y]=='W') return 0;
    for(int i=0;i<4;i++){
        int mx=x+dir[i][0],my=y+dir[i][1];
        if(!judge(mx,my)) continue;
        if(cc[mx][my]=='N'){
            //printf("N.\n");
            int d=(0+time)%4;
            if(abs(d-i)==2) return 1;
        }
        else if(cc[mx][my]=='E'){
            //printf("E.\n");
            int d=(1+time)%4;
            if(abs(d-i)==2) return 1;
        }
        else if(cc[mx][my]=='S'){
            //printf("S.\n");
            int d=(2+time)%4;
            if(abs(d-i)==2) {
                //printf("S.time=%d i=%d cc=%c\n",time,i,cc[x][y]);
                return 1;
            }
        }
        else if(cc[mx][my]=='W'){
           // printf("W.\n");
            int d=(3+time)%4;
            if(abs(d-i)==2) return 1;
        }
    }
    return -1;
}

void bfs(int sx,int sy)
{
    int ans=INF;
    bool flag;
    priority_queue<ppp> que;
    ppp P;
    P.x=sx;    P.y=sy;    P.ti=0;
    que.push(P);
    while(que.size()){
        P=que.top(); que.pop();
        if(cc[P.x][P.y]=='T'){
            ans=min(ans,P.ti);
            break;
        }
        for(int i=0;i<4;i++){
            int mx=P.x+dir[i][0],my=P.y+dir[i][1];
            if(!judge(mx,my)) continue;
            ppp midP;
            midP.x=mx; midP.y=my; midP.ti=P.ti;
            int tt=cal(P.x,P.y,P.ti),mtt=cal(midP.x,midP.y,P.ti);
            if(tt==0){
                midP.ti+=3;
            }
            else if(tt==1){
                midP.ti+=3;
                ppp midP2=P;
                midP2.ti++;
                if(midP2.ti<vis[midP2.x][midP2.y][midP2.ti%4]){
                    vis[midP2.x][midP2.y][midP2.ti%4]=midP2.ti;
                    que.push(midP2);
                }
            }
            else if(tt==-1){
                //printf(".-1.\n");
                if(mtt==0) midP.ti+=3;
                else if(mtt==1){
                    ppp midP2=P;
                    midP2.ti++;
                    if(midP2.ti<vis[midP2.x][midP2.y][midP2.ti%4]){
                        vis[midP2.x][midP2.y][midP2.ti%4]=midP2.ti;
                        que.push(midP2);
                    }
                    midP.ti+=3;
                }
                else midP.ti++;
            }
            if(midP.ti<vis[midP.x][midP.y][midP.ti%4]){
                vis[midP.x][midP.y][midP.ti%4]=midP.ti;
                que.push(midP);
            }
        }
    }
    if(ans==INF) printf("-1\n");
    else printf("%d\n",ans);
}

int main()
{
    int T;
    scanf("%d",&T);
    for(int kk=1;kk<=T;kk++){
        scanf("%d",&N);
        for(int i=0;i<N;i++) scanf("%s",cc[i]);
        for(int i=0;i<N;i++) for(int j=0;j<N;j++) for(int k=0;k<4;k++) vis[i][j][k]=INF;
        printf("Case #%d: ",kk);
        for(int i=0;i<N;i++){
            int j;
            for(j=0;j<N;j++) if(cc[i][j]=='M'){bfs(i,j);break;}
            if(cc[i][j]=='M') break;
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值