HDU 2531 Catch him(BFS)

题目

在美式足球中,四分卫负责指挥整只球队的进攻战术和跑位,以及给接球员传球的任务。四分卫是一只球队进攻组最重要的球员,而且一般身体都相对比较弱小,所以通常球队会安排5-7名大汉来保护他,其中站在四分卫前方、排成一线的5名球员称为进攻锋线,他们通常都是135公斤左右的壮汉。

对防守方来说,攻击对手的四分卫当然是最直接的限制对手进攻的方法。如果效果好,就可以在对方四分卫传球之前将其按翻在地,称之为擒杀。擒杀是最好的鼓舞防守队士气的方法,因为对方连传球的机会都没有,进攻就结束了,还必须倒退一些距离开球。凶狠的擒杀甚至能够将对方的四分卫弄伤,从而迫使对方更换这个进攻核心。
在本题中,输入给出准备擒杀四分卫的防守球员的位置、对方每个进攻锋线球员的位置以及对方四分卫的位置,你的任务是求出这名准备擒杀的防守球员至少要移动多少步,才能够擒杀对方四分卫。
假设对方进攻锋线和四分卫在这个过程中都不会移动。只有1名防守球员,防守球员只要碰到对方四分卫就算擒杀。
所有的球员都是一块连续的、不中空的2维区域。防守球员不可以从进攻锋线的身体上穿过,也不可以从界外穿过(只能走空地)。
防守队员不可以转动身体,只能平移。防守队员的身体所有部分向同一个方向(上、下、左、右)移动1格的过程叫做1步。

Input
输入包含多组数据。每组数据第一行都是两个整数H,W(0<H,W<=100),表示整个区域的高度和宽度,H=W=0表示输入结束。接下来有H行,每行W个字符。每个字符如果是’.’,表示这里是空地,如果是’O’,表示是进攻锋线队员的身体,如果是’D’,表示是准备擒杀的防守球员的身体,如果是’Q’,表示是四分卫的身体。
输入保证符合上面的条件。防守球员的身体总共不超过20格。

Output
对每组数据,输出包含擒杀所需最少步数的一行。如果不能擒杀,输出带’Impossible’的一行。

Sample Input
6 6
.Q…
QQ…OO
.OO…O
…O.O
OO.O…
…DD
7 7
.Q…
QQ.OOO.
…O…
O…
OO…OO.
.O…
…DD
0 0

Sample Output
Impossible
9

解题思路

1.首先,根据题目的要求,求解最少步数!!!直接采用BFS(广搜)
2.初始位置和终点位置都有多个位置,则采用化繁为简,从初始位置的一个点出发,建立该点与其它初始位置的关系,以该点进行广搜(注意剪枝也要已该点为对象),只要该点或关联点到达指定位置即可,输出最少步数!!!

踩坑

1.一开始没注意,防守球员的身体总共不超过20格,导致按防守球员的身体定长进行计算;
2.剪枝的问题,明明自己是按一个点进行广搜的,却让防守球员的身体的其它点也列为剪枝的对象。

AC代码

#include <bits/stdc++.h>

using namespace std;

char room[150][150];
int W,H,num;
int judge[150][150];
int dir[4][2] = {-1,0,1,0,0,-1,0,1};
int fx[25];
int fy[25];
struct node
{
    int x;
    int y;
    int step;
};

//1.输入地图,并找到初始位置
//2.搜索,并判断

bool is_map(int x,int y)    //该点是否能走
{
    if(room[x][y] != 'O')
        return true;
    return false;
}

bool is_room(int x,int y)   //是否越界
{
    if(x >= 0 && x < H && y >= 0 && y < W)
        return true;
    return false;
}

bool is_tot(int x,int y)    //整体是否能走
{
    if(!is_room(x,y) || !is_map(x,y))
        return false;
    for(int i = 1 ; i < num ; i++)
    {
        int dx = x-fx[i];
        int dy = y-fy[i];
        if(!is_room(dx,dy) || !is_map(dx,dy))
            return false;
    }
    return true;
}

bool daoda(int x,int y)		//是否到达目标位置
{
    if(room[x][y] == 'Q') return true;
    for(int i = 1 ; i < num ; i++)
    {
        int dx = x-fx[i];
        int dy = y-fy[i];
        if(room[dx][dy] == 'Q') return true;
        if(!is_room(dx,dy) || !is_map(dx,dy))
            return false;
    }
    return false;
}

bool is_lead(int x,int y)	//整合即为该步是否能走
{
    if(is_map(x,y)&&is_room(x,y)&&is_tot(x,y))
        return true;
    return false;
}

void Bfs(int x,int y)		//基本广搜
{
    node start,next;
    queue<node>q;
    start.x = x;
    start.y = y;
    start.step = 0;
    q.push(start);
    while(!q.empty())
    {
        start = q.front();
        if(daoda(start.x,start.y))
        {
            cout << start.step <<  endl;
            return;
        }
        q.pop();
        for(int i = 0 ; i < 4 ; i++)
        {
            next.x = start.x+dir[i][0];
            next.y = start.y+dir[i][1];
            if(is_lead(next.x,next.y) && judge[next.x][next.y] == 0)
            {
                next.step = start.step+1;
                q.push(next);
                judge[next.x][next.y] = 1;
            }
        }

    }
    cout << "Impossible" << endl;
}

void inputroom()
{
    int flag = 1;
    int dx,dy;
    for(int i = 0 ; i < H ; i++)
    {
        for(int j = 0 ; j < W ; j++)
        {
            cin >> room[i][j];
            if(room[i][j] == 'D' && flag)	//找到第一个D的位置,设置为广搜的起始点
            {
                num++;
                flag = 0;
                dx = i;
                dy = j;
            }
            else if(room[i][j] == 'D')		//建立该点和其它点之间的联系
            {
                fx[num] = dx-i;
                fy[num] = dy-j;
                num++;
            }
        }
    }
    Bfs(dx,dy);
}

void sovle()
{
    while(cin >> H >> W)
    {
        num = 0;
        memset(judge,0,sizeof(judge));		//注意每次的初始化
        if(H == 0 && W == 0)  break;
        inputroom();

    }
}

int main()
{
    sovle();
    return 0;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值