题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5335
题面:
2 2 2 11 11 3 3 001 111 101
111 101
//如果之前的搜索最远的1用的是深搜,那么需扩栈,如果是广搜就不必了
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
//map存原图
char map[1005][1005];
//vis访问标记,able标识该点是否可以从0可达
bool vis[1005][1005],able[1005][1005];
//path记录路径,cnt为路径的下标
int t,n,m,xx,yy,path[2010],cnt=0;
//dir为四个方向
int dir[4][2]={-1,0,0,1,1,0,0,-1};
//每个节点,即位置
struct node
{
int x,y;
node (int xx,int yy)
{
x=xx;
y=yy;
}
};
//判断是否越界
bool Inside(int x,int y)
{
if(x>=0&&x<n&&y>=0&&y<m)
return true;
return false;
}
queue <node> q;
//搜索能够通过0达到的位置
void bfss()
{
int tx,ty;
q.push(node(0,0));
node tmp(0,0);
while(!q.empty())
{
tmp=q.front();
q.pop();
//4个方向扩展
for(int i=0;i<4;i++)
{
tx=tmp.x+dir[i][0];
ty=tmp.y+dir[i][1];
if(Inside(tx,ty)&&!vis[tx][ty])
{
vis[tx][ty]=1;
if(map[tx][ty]=='0')
{
//able代表该点可达
able[tx][ty]=1;
q.push(node(tx,ty));
}
}
}
}
}
//qe存过程中的点,v0存0的位置,v1存1的位置
queue <node> qe;
vector <node> v0;
vector <node> v1;
bool rea[1005][1005];
//搜索最短,且字典序最小的路径
void bfs()
{
while(!qe.empty())
qe.pop();
int tx,ty,sz;
bool sign=false;
//rea访问标记
memset(rea,0,sizeof(rea));
node tmp(0,0);
while(1)
{
//如果之前出现了可达的0
if(v0.size())
{
//那么当前路径位置就取0
path[cnt++]=0;
sz=v0.size();
for(int i=0;i<sz;i++)
qe.push(v0[i]);
}
//如果没有出现过0,都是1
else
{
//那么当前路径位置就取1
path[cnt++]=1;
sz=v1.size();
for(int i=0;i<sz;i++)
qe.push(v1[i]);
}
//清空
v0.clear();
v1.clear();
//将qe中的点的下一步位置存到v0,v1中
while(!qe.empty())
{
tmp=qe.front();
qe.pop();
//向下
tx=tmp.x+1;
ty=tmp.y;
//因为rea数组,每个点最多进入队列一次
if(Inside(tx,ty)&&(!rea[tx][ty]))
{
rea[tx][ty]=1;
if(map[tx][ty]=='0')
v0.push_back(node(tx,ty));
else
v1.push_back(node(tx,ty));
}
//向右
tx=tmp.x;
ty=tmp.y+1;
if(Inside(tx,ty)&&(!rea[tx][ty]))
{
rea[tx][ty]=1;
if(map[tx][ty]=='0')
v0.push_back(node(tx,ty));
else
v1.push_back(node(tx,ty));
}
}
//没有点了,说明已到达终点
if((v0.size()==0)&&(v1.size()==0))
break;
}
}
int main()
{
int minn=0,x,y,z=1;
bool flag;
scanf("%d",&t);
while(t--)
{
//读入
cnt=0;
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
{
scanf("%s",map[i]);
}
//起点为1,从起点开始寻路
if(map[0][0]=='1')
{
v1.push_back(node(0,0));
}
//起点为0,先找到最远的点们,然后开始寻路
else
{
memset(vis,0,sizeof(vis));
memset(able,0,sizeof(able));
bfss();
vis[0][0]=able[0][0]=1;
minn=0;
flag=false;
//从离终点最近的斜线开始扫
for(int i=1;i<=m;i++)
{
for(int j=1;j<=i;j++)
{
x=n-j;
y=m-(i+1-j);
//只有x+y最大的且合法的点,才会被加入队列(此处为向量)
if(x+y>=minn)
{
//该点左边或者上边是可达的
if((Inside(x-1,y)&&able[x-1][y])||(Inside(x,y-1)&&able[x][y-1]))
{
minn=x+y;
if(map[x][y]=='1')
v1.push_back(node(x,y));
}
}
else
{
flag=true;
break;
}
}
if(flag)break;
}
}
//
if(!flag)
{
//扫第一条边那的斜线
for(int i=n-1;i>=1;i--)
{
for(int j=1;j<=i;j++)
{
if(x+y>=minn)
{
x=i-j;
y=j-1;
if((Inside(x-1,y)&&able[x-1][y])||(Inside(x,y-1)&&able[x][y-1]))
{
minn=x+y;
if(map[x][y]=='1')
v1.push_back(node(x,y));
}
}
else
{
flag=true;
break;
}
}
}
}
//如果有全都为0的路径,直接输出0
if(v1.size()==0)
{
printf("0\n");
continue;
}
//寻路
bfs();
//输出
for(int i=0;i<cnt;i++)
printf("%d",path[i]);
printf("\n");
}
return 0;
}版权声明:本文为博主原创文章,未经博主允许不得转载。
HDU 5335 Walk Out (搜索+贪心,超详解)经典
原文地址:http://blog.csdn.net/david_jett/article/details/47185303