hdu 2531 (整块BFS)

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

以整块里面的最左上角的点作为代表,将所有边界上的点和代表点的相对距离存储在结构体里面,就转变成一个点的BFS了,然后改写一下check函数。

让我想到了像素游戏里面人物的移动,不知道是不是就是这样设计的。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <stack>

using namespace std;

#define FOR(i,k,n) for(int i=k;i<n;i++)
#define FORR(i,k,n) for(int i=k;i<=n;i++)
#define scan(a) scanf("%d",&a)
#define scann(a,b) scanf("%d%d",&a,&b)
#define scannn(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define mst(a,n)  memset(a,n,sizeof(a));
#define ll long long
#define N 105
#define mod 1000000007
#define INF 0x3f3f3f3f

int n,m;
char map[N][N];
int vis[N][N];
int uIndex,dIndex,lIndex,rIndex;
int go[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
int flag;

typedef struct Point
{
    int x,y;
    int step;
    //Point(int xx,int yy):x(xx),y(yy){}
}point;

struct node
{
    point border[20];
    int index;
}D[4];


bool check(int x,int y,int dir)
{

    int j=0;
    for(;j<D[dir].index;j++)
    {
        int xx=x+D[dir].border[j].x;
        int yy=y+D[dir].border[j].y;
        if(!(xx>=0&&xx<n&&yy>=0&&yy<m&&map[xx][yy]!='O'))
            break;
        else
        {
            if(map[xx][yy]=='Q')
                flag=1;
        }
    }
    if(j<D[dir].index)
    {
        flag=0;
        return false;
    }
    else
        return true;
}


int Bfs(int sx,int sy)
{
    point s; s.x=sx; s.y=sy; s.step=0;

    queue<point> q;
    q.push(s);
    while(!q.empty())
    {
        point cur=q.front();
        q.pop();
        //根结点全是D,不包含Q,即若有解的话,ans>=1,所以根结点不用check,故check函数可以移到for循环里面,
        //检测所有产生的子节点即可
        for(int i=0;i<4;i++)
        {
            int x=cur.x+go[i][0];
            int y=cur.y+go[i][1];
            if(!vis[x][y]&&check(x,y,i))
            {
                vis[x][y]=1;
                point tmp;
                tmp.x=x; tmp.y=y;
                tmp.step=cur.step+1;
                if(flag)
                    return tmp.step;
                q.push(tmp);
            }
        }
    }
    return -1;
}

int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);

    while(~scann(n,m)&&!(!n&&!m))
    {
        mst(vis,0);
        mst(map,'.');//之前没加这句,导致判断D的边界的时候,因上一组数据残留的字符'D'
                    //而造成了与map边界重合的D的边界的部分丢失
        flag=0;
        uIndex=0,dIndex=0,lIndex=0,rIndex=0;
        int first=0,sx=-1,sy=-1;
        FOR(i,0,n)
        {
            getchar();
            FOR(j,0,m)
            {
                scanf("%c",&map[i][j]);
                if(map[i][j]=='D')
                {
                    if(!first){
                        first=1;
                        sx=i; sy=j;
                    }
                    if(map[i][j+1]!='D')
                    {
                        D[0].border[rIndex].x=i-sx;
                        D[0].border[rIndex].y=j-sy;
                        rIndex++;
                    }
                    if(map[i+1][j]!='D')
                    {
                        D[1].border[dIndex].x=i-sx;
                        D[1].border[dIndex].y=j-sy;
                        dIndex++;
                    }
                    if(map[i][j-1]!='D')
                    {
                        D[2].border[lIndex].x=i-sx;
                        D[2].border[lIndex].y=j-sy;
                        lIndex++;
                    }
                    if(map[i-1][j]!='D')
                    {
                        D[3].border[uIndex].x=i-sx;
                        D[3].border[uIndex].y=j-sy;
                        uIndex++;
                    }
                }
            }
        }
        D[0].index=rIndex; D[1].index=dIndex; D[2].index=lIndex; D[3].index=uIndex;
        vis[sx][sy]=1;
        int ans=Bfs(sx,sy);
        if(ans!=-1)
            printf("%d\n",ans);
        else
            printf("Impossible\n");
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值