【题】【搜索】NKOJ3868 二进制迷宫

7 篇文章 0 订阅

NKOJ3868 二进制迷宫
时间限制 : - MS 空间限制 : 165536 KB
评测说明 : 1s

问题描述
何老板来到一个n*m的方格迷宫,每个格子中的数字要么是0要么是1。现在他从左上角坐标为(1,1)的格子出发,走到右下角的坐标为(n,m)的格子,他可以沿上下左右四个方向行走。每到一个格子,他就用本子记录下里面的数字。当他到达终点的时候,将得到一个由0和1构成的序列,他会把这个序列看做一个二进制数。
何老板要求这个二进制数尽可能小,请你计算并输出这个二进制数。

输入格式
第一行,两个整数n和m
接下来一个n*m的01矩阵,数字间无空格间隔

输出格式
一个二进制数,表示最优结果。前导0不输出。

样例输入 1
5 5
01111
01000
01010
01010
00011

样例输出 1
1

样例输入 2
3 3
001
111
101

样例输出 2
101

提示
【数据范围】
对于30%的数据:1≤n,m≤100
对于100%的数据:1≤n,m≤1000

来源 改编自multi 2015 walk out

先宽搜预处理出所有从左上角出发能到达的1,找出离终点曼哈顿距离最近的1们。
这些1应该是连成了一条斜线,所以依次讨论下方的斜线们,若有0就只讨论0,没有0就都讨论。

#include<cstdio>
#include<iostream>
#include<cmath>
#include<bitset>
#include<queue>
#include<algorithm>
#include<vector>
using namespace std;
#define END return 0
const int need=1003;

int n,m;
char ma[need][need];
//.....................................................
int kx[]={0,0,1,-1},ky[]={1,-1,0,0};

struct fy
{
    int a,b,val;
};

vector<fy> w;
#define pb(a,b) push_back((fy){a,b,n-a+m-b})
bool vis[need][need];
queue<fy> q; 

bool end_=false;

void bfs(int x,int y)
{
    int xx,yy;
    q.push((fy){x,y});
    while(!q.empty())
    {
        x=q.front().a,y=q.front().b;
        if(x==n&&y==m) 
        {
            end_=true;//如果一开始就搜到终点,输出0
            return ;
        }
        q.pop();
        for(int i=0;i<4;i++)
        {
            xx=x+kx[i],yy=y+ky[i];
            if(ma[xx][yy]=='0'&&!vis[xx][yy]) 
            {
                vis[xx][yy]=true;
                q.push((fy){xx,yy});
            }
            else if(ma[xx][yy]=='1'&&!vis[xx][yy])
            {
                vis[xx][yy]=true;
                w.pb(xx,yy);
            }
        } 
    }

}
//.....................................................
bool way(const fy &a,const fy &b)
{
    return a.val<b.val;
}
//.....................................................
bool use[need][need];
//.....................................................

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",&ma[i][1]);
    }
    if(ma[1][1]=='0')
    {
        bfs(1,1);
        sort(w.begin(),w.end(),way);
        if(w.size()==0||end_) //直接能到终点
        {
            putchar('0');
            END;
        }
        int biao=w.begin()->val;
        while(w.back().val>biao) w.pop_back();
    }
    else w.pb(1,1);//左上角为1
    putchar('1');
    bool get0,get0la;
    for(int i=1,nn=w.begin()->val,vt,x,y;i<=nn;i++)
    {
        get0=false;
        vt=w.begin()->val;
        while(w.begin()->val==vt)
        {
            x=w.begin()->a,y=w.begin()->b;
            w.erase(w.begin());
            if(get0la&&ma[x][y]=='1') continue;//该层中存在0,当前为1就不用讨论了
            if(x+1<=n&&!use[x+1][y])
            {
                use[x+1][y]=true;
                w.pb(x+1,y);
                if(ma[x+1][y]=='0') get0=true;
            }
            if(y+1<=m&&!use[x][y+1])
            {
                use[x][y+1]=true;
                w.pb(x,y+1);
                if(ma[x][y+1]=='0') get0=true;
            }
        }
        putchar(get0 ? '0':'1');
        get0la=get0;//记录该层是否存在0,以便下一层讨论
    }
    END;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值