设计与算法:鸣人和佐助

已知一张地图(以二维矩阵的形式表示)以及佐助和鸣人的位置。地图上的每个位置都可以走到,只不过有些位置上有大蛇丸的手下,需要先打败大蛇丸的手下才能到这些位置。鸣人有一定数量的查克拉,每一个单位的查克拉可以打败一个大蛇丸的手下。假设鸣人可以往上下左右四个方向移动,每移动一个距离需要花费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

30    20    2
##@****#*#*****#**##
##*#*#*****#***#*###
#*####***##*##**#***
**#*##*##***##**#*#*
**####**###***#*###*
**###*#***#**#***#**
#**#####*##*#*#**#**
*#***##****#*****##*
***###*##*######****
##*#**#**####*##**#*
#**##****#****#**##*
+##*#####*#*#*#*#*##
#*##*#**##*###*#*#**
*##****###*#*####**#
**##**#*#*#**###*#*#
**#****#*##**##*###*
*##*****#****#*##**#
#**###*##*#####****#
***##*###*###****#*#
#**#**##*###*####*#*
#***#*##*##*#*#****#
###*##***#*##**#*#**
#*#*###**####*##**##
###*####***##*###***
#*#*#**#*#*#*######*
*##*###*####**#**##*
*#######****#**###*#
####*#*#*#**#*##****
*#*#*#####*##***#*##
##*#*#**#*##*###***#
15

还有一个长的不粘了,哈哈。就是用查克拉作标志位的问题

//开个结构体保存位置和步数以及查克拉 
//一个字符数组保存符号,
//就是忘了左助是个+号了,检查了多次才找到原因 
//开始记下鸣人和左助的位置 
//Writed by Wangzhimin Date:2023/12/21 
//在同一层次下,优先考虑不用查克拉到的位置;在到一个点时,要考虑剩余的查克拉
//所以,标志位用剩余的查克拉来表示。
//看似代码多,实多是相似的。如检查向上时,首先判断边界,!0吗或是(如果走过)ckl比当前小吗 ,字符是什么 
#include<bits/stdc++.h>
using namespace std;
int N,M,T;
struct maze{
    int x,y;//坐标,行列的位置 
    int steps;//几步 
    int ckl;//查克拉 
    maze(int xx,int yy,int ss,int c):x(xx),y(yy),steps(ss),ckl(c){
    }//输入结构体用,仿照的,大概这个意思 
};
char tu[205][205];//开个字符数组  
int visited[205][205];
int main()
{
    cin>>M>>N>>T;//数组大小及查克拉 
    int mx,my,zx,zy;//存位置 
    for(int i=0;i<M;i++)
        for(int j=0;j<N;j++)
        {
            cin>>tu[i][j];
            if(tu[i][j]=='@')//鸣人的位置 
            {
                mx=i;
                my=j;
            }
            if(tu[i][j]=='+')//左助的位置 
            {
                zx=i;
                zy=j;
            }
        }
    
    queue <maze> q;//队列 
    q.push(maze(mx,my,0,T));//鸣人入队列 
  
    while(!q.empty()){
        maze s=q.front();
    //    cout<<s.x<<" "<<s.y<<" "<<s.steps<<" "<<s.ckl<<endl;
        if(s.x==zx&&s.y==zy){//找到左助的位置,就输出 
            cout<<s.steps<<endl;
            return 0;
        }
        else
        {//先判断走*或是+的位置,相同层次下。再判断走#的地方,尽量保存查克拉
        //以s点出发,向上,向下,向左,向右分别判断
        //因为走到一个点,在相同层次下,尽量不用查克拉,所以做了双倍的判断
        //以余下的查克拉作为标志,如果再到这个点时,如果那路剩下的查克拉多,就再广搜 
            if(s.x-1>=0&&(!visited[s.x-1][s.y]||visited[s.x-1][s.y]<=s.ckl)&&(tu[s.x-1][s.y]=='*'||tu[s.x-1][s.y]=='+'))//up
            {            
                    q.push(maze(s.x-1,s.y,s.steps+1,s.ckl));
                    visited[s.x-1][s.y]=s.ckl+1;
                }
            if(s.x+1<M&&(!visited[s.x+1][s.y]||visited[s.x+1][s.y]<=s.ckl)&&(tu[s.x+1][s.y]=='*'||tu[s.x+1][s.y]=='+'))//down
            {            
                    q.push(maze(s.x+1,s.y,s.steps+1,s.ckl));
                    visited[s.x+1][s.y]=s.ckl+1;
                }
            if(s.y-1>=0&&(!visited[s.x][s.y-1]||visited[s.x][s.y-1]<=s.ckl)&&(tu[s.x][s.y-1]=='*'||tu[s.x][s.y-1]=='+'))//left
            {
                    q.push(maze(s.x,s.y-1,s.steps+1,s.ckl));
                    visited[s.x][s.y-1]=s.ckl+1;
                }
            if(s.y+1<N&&(!visited[s.x][s.y+1]||visited[s.x][s.y+1]<=s.ckl)&&(tu[s.x][s.y+1]=='*'||tu[s.x][s.y+1]=='+'))//right
            {
                    q.push(maze(s.x,s.y+1,s.steps+1,s.ckl));
                    visited[s.x][s.y+1]=s.ckl+1;
                }
                //使用查克拉到的标志为 
                   if(s.x-1>=0&&!visited[s.x-1][s.y]&&tu[s.x-1][s.y]=='#'&&s.ckl>=1)//fight and walk
                {
                    q.push(maze(s.x-1,s.y,s.steps+1,s.ckl-1));
                    visited[s.x-1][s.y]=s.ckl+1;
                }                
                   if(s.x+1<M&&!visited[s.x+1][s.y]&&tu[s.x+1][s.y]=='#'&&s.ckl>=1)//fight and walk
                {
                    q.push(maze(s.x+1,s.y,s.steps+1,s.ckl-1));
                    visited[s.x+1][s.y]=s.ckl+1;
                }            
                   if(s.y-1>=0&&!visited[s.x][s.y-1]&&tu[s.x][s.y-1]=='#'&&s.ckl>=1)//fight and walk
                {
                    q.push(maze(s.x,s.y-1,s.steps+1,s.ckl-1));
                    visited[s.x][s.y-1]=s.ckl+1;
                }            
                    if(s.y+1<N&&!visited[s.x][s.y+1]&&tu[s.x][s.y+1]=='#'&&s.ckl>=1)//fight and walk
                {
                    q.push(maze(s.x,s.y+1,s.steps+1,s.ckl-1));
                    visited[s.x][s.y+1]=s.ckl+1;
                }
            
            q.pop();
        }
        
    }
    cout<<"-1"<<endl;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值