poj 4115(BFS的特殊标记)

佐助被大蛇丸诱骗走了,鸣人在多少时间内能追上他呢?


已知一张地图(以二维矩阵的形式表示)以及佐助和鸣人的位置。地图上的每个位置都可以走到,只不过有些位置上有大蛇丸的手下,需要先打败大蛇丸的手下才能到这些位置。鸣人有一定数量的查克拉,每一个单位的查克拉可以打败一个大蛇丸的手下。假设鸣人可以往上下左右四个方向移动,每移动一个距离需要花费1个单位时间,打败大蛇丸的手下不需要时间。如果鸣人查克拉消耗完了,则只可以走到没有大蛇丸手下的位置,不可以再移动到有大蛇丸手下的位置。佐助在此期间不移动,大蛇丸的手下也不移动。请问,鸣人要追上佐助最少需要花费多少时间?

Input输入的第一行包含三个整数:M,N,T。代表M行N列的地图和鸣人初始的查克拉数量T。0 < M,N < 200,0 ≤ T < 10 
后面是M行N列的地图,其中@代表鸣人,+代表佐助。*代表通路,#代表大蛇丸的手下。Output输出包含一个整数R,代表鸣人追上佐助最少需要花费的时间。如果鸣人无法追上佐助,则输出-1。Sample Input
样例输入14 4 1#@##**#####+****样例输入24 4 2#@##**#####+****
Sample Output
样例输出
16
样例输出
24

求最短步数,最短时间,BFS,当然也可以用剪枝+DFS来做,这里我只用BFS,其实这道题一看就是BFS但是有一个特别的细节没有注意,导致自己WA好几次,好几个小时吧,愣是没想出来,就是查克拉的处理,对于一般的迷宫问题来说就一种情况,你走过就不能再走了,要不就是浪费时间或者死循环。一开始我就像平常一样用一个二位数组进行简单的标记。来确定哪些点走过,哪些点没有走过,但是这样有一个问题,对于这一组数据

10 10 1
@#********
*******###
*******##*
*******##*
*******##*
*******##*
*******##*
*******##*
*******##*
*******##+

如果用一个二维数组来表示走过的点不能再走的话,输出的答案是-1,很明显手动模拟一下就发现这个思路是错误的,其实走过的点是可以再走的,对于广搜种搜索形式来说,总会有几个点乱走,导致最佳点被走过。但是可以走有条件,否则会死循环出不来。在这里有两种处理走过的坐标点,一个使用三维数组,另一种是使用二维数组,下面我先用三维数组:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
#define me(a,b)    memset(a,b,sizeof(a))
#define reph(i,b,c)   for(int i=b;i<=c;i++)
char dp[304][304];
int yy[]={0,0,1,-1};
int xx[]={1,-1,0,0};
int sum=0;
int MAX=0x3f3f3f3f;
int n;
int m;
bool v[300][300][300];//三维数组表示是否在(x,y)这一点,查克拉为ckl的名人来过,这样就处理了死循环的问题
int t;                //拿上面的样例来说肯定会有查克拉为0和1的点都经过(1,3)这个点(坐标数组从(1,1)开始),那么两次经过都不影响了
struct node
{
    int x;
    int y;
    int ckl;
    int step;
}now;
queue<node>q;
bool check(node no)
{
    if(no.x>0&&no.x<=m&&no.y>0&&no.y<=n&&no.ckl>=0)
        if(!v[no.x][no.y][no.ckl])
        return true;
    return false;
}
int bfs()
{
    node next;
    while(q.size())
    {
        now=q.front();
        q.pop();
        if(dp[now.x][now.y]=='+')
            return now.step;
        for(int i=0;i<4;i++)
        {
            next.x=now.x+xx[i];
            next.y=now.y+yy[i];
            next.ckl=now.ckl;
            if(check(next))
            {
                if(dp[next.x][next.y]=='#'){
                    if(next.ckl-1>=0){
                            next.step=now.step+1;
                            next.ckl=now.ckl-1;
                            v[next.x][next.y][next.ckl]=1;
                        q.push(next);
                    }
                }
                else if(dp[next.x][next.y]=='*'||dp[next.x][next.y]=='+'){
                        v[next.x][next.y][next.ckl]=1;
                   next.step=now.step+1;
                    q.push(next);
                }

            }
        }
    }
    return -1;
}
int main()
{
   // cin>>m>>n>>t;
   scanf("%d%d%d",&m,&n,&t);
   getchar();
    me(dp,0);
    int mingren_x,mingren_y;
    reph(i,1,m)
    {
        reph(j,1,n)
        {
        scanf("%c",&dp[i][j]);
       //    cin>>dp[i][j];
        if(dp[i][j]=='@')
        {
        mingren_x=i;
        mingren_y=j;
        dp[i][j]='*';
        }
        }
        getchar();
    }
    now.x=mingren_x;
    now.y=mingren_y;
    now.ckl=t;
    now.step=0;
    q.push(now);
    v[mingren_x][mingren_y][now.ckl]=1;
    cout<<bfs()<<endl;
//    reph(i,1,m)
//    {
//        reph(j,1,n)
//        cout<<dp[i][j];
//        cout<<endl;
//    }
    return 0;
}

下面使用二维数组

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
#define me(a,b)    memset(a,b,sizeof(a))
#define reph(i,b,c)   for(int i=b;i<=c;i++)
char dp[304][304];
int yy[]={0,0,1,-1};
int xx[]={1,-1,0,0};
int sum=0;
int MAX=0x3f3f3f3f;
int n;
int m;
int v[300][300];//这里二维数组表示到达(x,y)这一点ckl的最大值,为什么这么定义呢,因为如果你的ckl为0时到达改点,那么比0还要大的肯定也能到达此处
int t;//有ckl总比没有快一点追上佐助吧,因此v数组开始要设为-1
struct node
{
    int x;
    int y;
    int ckl;
    int step;
}now;
queue<node>q;
bool check(node no)
{
    if(no.x>0&&no.x<=m&&no.y>0&&no.y<=n)
        return true;
    return false;
}
int bfs()
{
    node next;
    while(q.size())
    {
        now=q.front();
        q.pop();
        if(dp[now.x][now.y]=='+')
            return now.step;
        for(int i=0;i<4;i++)
        {
            next.x=now.x+xx[i];
            next.y=now.y+yy[i];
            next.ckl=now.ckl;
            if(check(next))
            {
                if((next.ckl)>v[next.x][next.y])
            {
                if(dp[next.x][next.y]=='#'&&next.ckl-1>=0)
                {

                            next.step=now.step+1;
                            next.ckl=now.ckl-1;
                            v[next.x][next.y]=next.ckl;
                            q.push(next);
                }
                else if(dp[next.x][next.y]=='*'||dp[next.x][next.y]=='+')
                {
                        v[next.x][next.y]=next.ckl;
                   next.step=now.step+1;
                    q.push(next);
                }
            }

            }
        }
    }
    return -1;
}
int main()
{
   // cin>>m>>n>>t;
   scanf("%d%d%d",&m,&n,&t);
   getchar();
    me(dp,0);
    me(v,-1);
    int mingren_x,mingren_y;
    reph(i,1,m)
    {
        reph(j,1,n)
        {
        scanf("%c",&dp[i][j]);
       //    cin>>dp[i][j];
        if(dp[i][j]=='@')
        {
        mingren_x=i;
        mingren_y=j;
        dp[i][j]='*';
        }
        }
        getchar();
    }
    now.x=mingren_x;
    now.y=mingren_y;
    now.ckl=t;
    now.step=0;
    q.push(now);
    v[mingren_x][mingren_y]=t;
    cout<<bfs()<<endl;
//    reph(i,1,m)
//    {
//        reph(j,1,n)
//        cout<<dp[i][j];
//        cout<<endl;
//    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/c___c18/article/details/80961970
今日推荐