(牛客每日一题)[NOIP2017]棋盘--优先队列版广搜

我想从这道题开始展开对方向广搜各类题的总结;

普通的方向广搜就用单纯的队列然后根据题目的方向去搜就行;

但总有一些变形题在求最小值的时候,会限制或者是增加一些条件,使得一个点不能只单纯的遍历一次,或者说遍历玩这个点后还要进行折返之类的问题;

比如说这道题,这道题明显的要用广搜来写,网上很多题解也都是用广搜,至于颜色变换的地方也只是对是否入队的判断罢了,不是什么大问题。关键的地方就在于一个点从不同方向的地方遍历过来得到的所用的金钱是不同的。但广搜的弊端就在于这个点如果被遍历后就不能再被遍历了,如果继续遍历很容易超时或者超空间。所以这道题还要再引入贪心的思想。虽然还是进行遍历,但每次遍历开始的点必定是队列中金钱消耗量最少的点。

也就是说把队列换成优先队列,优先队列中排列顺序是所用金钱量从小到大,即可;

#include <bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxm=105;
int ans[maxm][maxm],sum[maxm][maxm];
bool flag[maxm][maxm];
int m,n;
struct node
{
    int x,y,color,fund;
    node(int x,int y,int color,int fund):x(x),y(y),color(color),fund(fund){}
    bool operator <(const node &w)const
    {
        return fund>w.fund;
    }
};
int dis[4][2]={1,0,0,1,-1,0,0,-1};
priority_queue<node> q;
int judge(int color,int pcolor)//黄1,红0,白-1,白黄-3,白红-2
{
    if(color==1&&pcolor==1) return 0;//黄黄
    else if(color==0&&pcolor==0) return 0;//红红
    else if(color==0&&pcolor==1||color==1&&pcolor==0) return 1;//2,黄红,红黄
    else if(color==-3&&pcolor==-1||color==-2&&pcolor==-1) return -1;//2,白黄白,白红白
    else if(color==1&&pcolor==-1||color==0&&pcolor==-1) return 2;//2,黄白,红白
    else if(color==-2&&pcolor==0) return 0;//1,白红红
    else if(color==-2&&pcolor==1) return 1;//1,白红黄
    else if(color==-3&&pcolor==1) return 0;//1,白黄黄
    else if(color==-3&&pcolor==0) return 1;//1,白黄红
    return 0;
}
void BFS()
{
    q.push({1,1,ans[1][1],0});
    sum[1][1]=0;
    while(q.size())
    {
        node tmp=q.top();
        q.pop();
        int x=tmp.x,y=tmp.y;
        if(flag[x][y]) continue;
        flag[x][y]=true;
        for(int i=0;i<4;i++)
        {
            int px=x+dis[i][0],py=y+dis[i][1];
            if(px>=1&&px<=m&&py>=1&&py<=m&&flag[px][py]==false)
            {
                int color=tmp.color;
                int t=judge(color,ans[px][py]);
                if(t!=-1)
                {
                    if(t==0) q.push({px,py,ans[px][py],tmp.fund+t});
                    else if(t==1) q.push({px,py,ans[px][py],tmp.fund+t});
                    else if(t==2)
                    {
                        if(ans[x][y]==0) q.push({px,py,-2,tmp.fund+t});
                        else if(ans[x][y]==1) q.push({px,py,-3,tmp.fund+t});
                    }
                    sum[px][py]=min(sum[px][py],tmp.fund+t);
                }
            }
        }
    }
}
int main()
{
    memset(ans,-1,sizeof(ans));
    memset(sum,INF,sizeof(sum));
    cin>>m>>n;
    for(int i=1;i<=n;i++)
    {
        int x,y,z;
        cin>>x>>y>>z;
        ans[x][y]=z;
    }
    BFS();
    /*for(int i=1;i<=m;i++)
    {
        for(int j=1;j<=m;j++)
        {
            cout<<sum[i][j]<<" ";
        }
        cout<<endl;
    }*/
    if(flag[m][m]) cout<<sum[m][m]<<endl;
    else cout<<-1<<endl;
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值