POJ4115:鸣人和佐助(广搜)

POJ4115:鸣人和佐助

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

输入
输入的第一行包含三个整数:M,N,T。代表M行N列的地图和鸣人初始的查克拉数量T。0 < M,N < 200,0 ≤ T < 10
后面是M行N列的地图,其中@代表鸣人,+代表佐助。*代表通路,#代表大蛇丸的手下。

输出
输出包含一个整数R,代表鸣人追上佐助最少需要花费的时间。如果鸣人无法追上佐助,则输出-1。

样例输入

样例输入1
4 4 1
#@##
**##
###+
****

样例输入2
4 4 2
#@##
**##
###+
****

样例输出

样例输出1
6

样例输出2
4

思路:

  • 首先此题是一个迷宫问题,是从某一个点要到某一个点,在这中间呢,又加入了消耗查克拉这个条件,我们可以按照深搜+剪枝来做,也可以直接用广搜来找最短路。

  • 那么这道题的状态是什么?是又鸣人的所在位置以及鸣人所剩查克拉决定的,(i,j,n),初始状态是(i0,j0,N),终止状态是(i,i,n),达到佐助位置即可。因为用广搜,所以到达即是最短。

  • 另外我们需要判重,用深搜只需要看这个点有没有走过,用广搜的话就要加入查克拉的消耗情况,所以是三维的visit数组。

AC代码

    #include<iostream>
    #include<cstdio>
    #include<queue>
    using namespace std;

    struct Node
    {
        int r,c;   //所在位置 
        int t;     //查克拉剩余
        int level; //所在层数,路径长度 
    };

    char map[210][210];          //地图
    int visit[210][210][15] = {0};    //判重数组
    int M,N,T;                  //地图大小,查克拉数量 

    int dir[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};   //方向数组  

    int main()
    {
        //分别代表鸣人和佐助的位置 
        int r1,c1;
        int r2,c2;

        scanf("%d %d %d",&M,&N,&T);
        for(int i = 0 ; i < M ; i ++)
        {
            for(int j = 0 ; j < N ; j ++)
            {
                cin>>map[i][j];
                if(map[i][j] == '@')
                {
                    r1 = i;
                    c1 = j;
                }

                if(map[i][j] == '+')
                {
                    r2 = i;
                    c2 = j;
                }
            }
        }

        visit[r1][c1][T] = 1;
        queue<struct Node> q;

        //初始状态入队
        Node node;
        node.r = r1; node.c = c1; node.level = 0; node.t = T;
        q.push(node);

        while(!q.empty())
        {
            Node temp = q.front();
            q.pop();

            //找到了 
            if(temp.r == r2 && temp.c == c2)
            {
                printf("%d\n",temp.level);
                return 0;   
            }   

            //没找到 入队所有关联节点
            for(int i = 0 ; i < 4 ; i ++)
            {
                Node temp2;
                temp2.r = temp.r + dir[i][0];
                temp2.c = temp.c + dir[i][1];
                if(temp2.r >= 0 && temp2.r < M && temp2.c >= 0 && temp2.c < N)
                {
                    //不越界

                    //若为# 并且查克拉够 并且没访问过 可访问 
                    if(map[temp2.r][temp2.c] == '#' && temp.t >= 1 && visit[temp2.r][temp2.c][temp.t - 1] == 0 )
                    {
                        temp2.t = temp.t - 1;
                        temp2.level = temp.level + 1;
                        q.push(temp2);
                        visit[temp2.r][temp2.c][temp2.t] = 1; 
                    } 

                    //不是# 并且未访问过 
                    else if(map[temp2.r][temp2.c] != '#' && visit[temp2.r][temp2.c][temp.t] == 0)
                    {
                        temp2.t = temp.t;
                        temp2.level = temp.level + 1;
                        q.push(temp2);
                        visit[temp2.r][temp2.c][temp2.t] = 1;
                    }

                }
            }

        } 

        //找不到 
        cout<<-1<<endl;

        return 0;
    }
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值