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