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;
}

阳光健康,就到这里吧。

原文地址:https://www.cnblogs.com/lichangjian/p/13030221.html