zoukankan      html  css  js  c++  java
  • P4554 小明的游戏 (洛谷) 双端队列BFS

    最近没有更新博客,全是因为英语,英语太难了QWQ

    洛谷春令营的作业我也不会(我是弱鸡),随机跳了2个题,难度不高,还是讲讲吧,学学新算法也好(可以拿来水博客)

    第一题就是这个小明的游戏

    小明最近喜欢玩一个游戏。给定一个 n×m的棋盘,上面有两种格子#和@。游戏的规则很简单:给定一个起始位置和一个目标位置,小明每一步能向上,下,左,右四个方向移动一格。如果移动到同一类型的格子,则费用是0,否则费用是1。请编程计算从起始位置移动到目标位置的最小花费。
    
    输入格式
    
    输入文件有多组数据。
    输入第一行包含两个整数n,m,分别表示棋盘的行数和列数。
    输入接下来的n行,每一行有m个格子(使用#或者@表示)。
    输入接下来一行有四个整数x1, y1, x2, y2 
    分别为起始位置和目标位置。
    当输入n,m均为0时,表示输入结束。
    
    输出格式
    
    对于每组数据,输出从起始位置到目标位置的最小花费。每一组数据独占一行。
    

    看起来像个广搜,但是我们仔细想想的话会发现,这玩意是有权值的,可能我走100格用的费用比你走一格用的都少,在最少费用的要求下,显然不能用普通的广搜。

    广搜的特点是把所有能走到的点全加进队列,为什么会用这种算法呢?,因为每走一步就需要一点费用的情况下,这样走花费最少。

    于是,我们可以想出一个主意,我们让队列双开口,把花费小的放在前面,花费大的放后面岂不美哉。但有的同学可能会疑惑(其实只有我),这样的话不是要手打堆排?不不不,里面最多有2种数,因为我们去查看大数的情况前先要看小数的情况,小数只能变成自己或者自己+1,如果是自己+1,变成大数,放在最后。如果不是,放在前面再来一遍。所以这个队列里只会有2种数。不用担心排序的问题。

    再来几个小提示就贴代码了:

    1、队列记得清空

    2、记得标记来过没

    3、有个东西叫deque,deque支持高效插入和删除容器的头部和尾部元素,因此也叫做双端队列(我用的就是这个)

    #include<iostream>
    #include<cstdio>
    #include<deque>
    using namespace std;
    char sz[505][505];
    long long a[500][500];
    long long n,m,qx,qy,zx,zy;
    long long fx[4]={0,0,1,-1};//控制移动的数组 
    long long fy[4]={1,-1,0,0};
    deque<int>qz;//3个双端队列 
    deque<int>xd;
    deque<int>yd;
    long long x,y,z;
    void sddl()
    {
        while(xd.empty()!=true&&yd.empty()!=true)//不空不走 
        {
            x=xd.front();//这个是获取队列的头部元素 
            y=yd.front();
            z=qz.front();
            if(x==zx&&y==zy)
            {
            	while (xd.empty()!=true)xd.pop_front();//清空队列,我之前因为没清空疯狂80分 
            	while (yd.empty()!=true)yd.pop_front();
            	while (qz.empty()!=true)qz.pop_front();
                cout<<z<<endl;
                return;
            }
            xd.pop_front();
            yd.pop_front();
            qz.pop_front();
            for(int i=0;i<4;i++)
            {
                if(x+fx[i]>=0&&x+fx[i]<n&&y+fy[i]>=0&&y+fy[i]<m)//判断越界 
                {
                    if(a[x+fx[i]][y+fy[i]]==0)//标记来过没 
                    {
                        a[x+fx[i]][y+fy[i]]=1;
                        if(sz[x+fx[i]][y+fy[i]]==sz[x][y])//走这个不需要花费,走起 
                        {
                            xd.push_front(x+fx[i]);//这个是插入到头部的意思 
                            yd.push_front(y+fy[i]);
                            qz.push_front(z);
                        }else//花费1点 
                        {
                            xd.push_back(x+fx[i]);//这个是插入到尾部的意思 
                            yd.push_back(y+fy[i]);
                            qz.push_back(z+1);
                        }  
                    }
                }
            }
        }
        return;
    }
    int main()
    {
        while(true)
        {
            scanf("%lld%lld",&n,&m);
            if(n==0&&m==0)
            {
                return 0;
            }
            for(int i=0;i<n;i++)
            {
                for(int j=0;j<m;j++)
                {
                    cin>>sz[i][j];
                    a[i][j]=0;
                }
            }
            scanf("%lld%lld%lld%lld",&qx,&qy,&zx,&zy);
            a[qx][qy]=1;//省一下 
            xd.push_front(qx);//这个是插入到头部的意思 
            yd.push_front(qy);
            qz.push_front(0);
            sddl();
        }
        return 0;
    }
    

    阳光健康,就到这里吧。

  • 相关阅读:
    常用正则表达式
    MySQL在大型网站的应用架构演变
    TCP窗口和拥塞控制
    【leetcode】1486. XOR Operation in an Array
    【leetcode】1481. Least Number of Unique Integers after K Removals
    【leetcode】1480. Running Sum of 1d Array
    【leetcode】1466. Reorder Routes to Make All Paths Lead to the City Zero
    【leetcode】1465. Maximum Area of a Piece of Cake After Horizontal and Vertical Cuts
    【leetcode】1464. Maximum Product of Two Elements in an Array
    【leetcode】1461. Check If a String Contains All Binary Codes of Size K
  • 原文地址:https://www.cnblogs.com/lichangjian/p/13030221.html
Copyright © 2011-2022 走看看