HDU 5335 Walk Out (搜索+贪心,超详解)经典

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5335

题面:

Walk Out

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)

Total Submission(s): 2355    Accepted Submission(s): 459

Problem Description

In an n?m
maze, the right-bottom corner is the exit (position
(n,m)
is the exit). In every position of this maze, there is either a
0
or a 1
written on it.

An explorer gets lost in this grid. His position now is
(1,1),
and he wants to go to the exit. Since to arrive at the exit is easy for him, he wants to do something more difficult. At first, he‘ll write down the number on position
(1,1).
Every time, he could make a move to one adjacent position (two positions are adjacent if and only if they share an edge). While walking, he will write down the number on the position he‘s on to the end of his number. When finished, he will get a binary number.
Please determine the minimum value of this number in binary system.

Input

The first line of the input is a single integer
T (T=10),
indicating the number of testcases.

For each testcase, the first line contains two integers
n
and m (1≤n,m≤1000).
The i-th
line of the next n
lines contains one 01 string of length m,
which represents i-th
row of the maze.

Output

For each testcase, print the answer in binary system. Please eliminate all the preceding
0
unless the answer itself is 0
(in this case, print 0
instead).

Sample Input

2
2 2
11
11
3 3
001
111
101

Sample Output

111
101

Author

XJZX

Source

2015 Multi-University Training Contest 4

解题:

比赛的时候,想了N久,都没想出来,一直想着深搜会跪,都没想着广搜。看了好多题解,都没看懂,决定自己写一发。

大致思路是,如果起始点是1的话,那么就是去广搜字典序最小的那条路。路径长为n+m-1,(因为起始为1之后,只会往下或往右走)通过标记VIS数组,从而达到了每个点只访问一次的目的,故时间复杂度(n*m)。因为等长的路径分布在斜线上(向下或向右都是到达同一条斜线),每次逐斜线扫过去。如果通过之前的点,在当前斜线可以到达0,那么就会选择0,没有0可选的情况下,才会选择1。(贪心策略)。

如果起始点不是1,那么就取广搜离起始点曼哈顿距离最远,也就是离目标点最近的1。因为,可能存在多个,那么全部加入队列即可。之后,就重复以上过程即可。

代码:

//如果之前的搜索最远的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;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-14 00:56:37

HDU 5335 Walk Out (搜索+贪心,超详解)经典的相关文章

hdu 5335 Walk Out (搜索)

题目链接: hdu 5335 Walk Out 题目描述: 有一个n*m由0 or 1组成的矩形,探险家要从(1,1)走到(n, m),可以向上下左右四个方向走,但是探险家就是不走寻常路,他想让他所走的路线上的0/1组成的二进数最小,现在要为矫情无比的探险家找最优路径咯. 解题思路: 对于二进制数,前导零是对数字大小没有任何影响的.当到不得不走1的时候就只能向下,或者向右走了.所以先搜索出来一直走零,能走到的最靠近终点的位置,然后在类似搜索,找出最优路径. 1 #include <queue>

HDU 5335——Walk Out——————【贪心】

Walk Out Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1292    Accepted Submission(s): 239 Problem Description In an n∗m maze, the right-bottom corner is the exit (position (n,m) is the exit).

POJ 1659 Frogs&#39; Neighborhood(可图性判定—Havel-Hakimi定理)【超详解】

Frogs' Neighborhood Time Limit: 5000MS   Memory Limit: 10000K Total Submissions: 9897   Accepted: 4137   Special Judge Description 未名湖附近共有N个大小湖泊L1, L2, ..., Ln(其中包括未名湖),每个湖泊Li里住着一只青蛙Fi(1 ≤ i ≤ N).如果湖泊Li和Lj之间有水路相连,则青蛙Fi和Fj互称为邻居.现在已知每只青蛙的邻居数目x1, x2, ..

CentOS6启动过程超详解分析

CentOS 6 开机流程--linux由kernel和rootfs组成.kernel负责进程管理.内存管理.网络管理.驱动程序.文件系统.安全等;rootfs由程序和glibc组成,完善操作系统的功能.同时linux内核的特点是模块化,通过对模块装载卸载可以对内核功能自定义.linux内核文件:/boot/vmlinuz-2.6.32-696.el6.x86_64 整体的流程 BIOS/开机自检 MBR引导(Boot Loader) 启动内核 启动第一个进程init 一.BIOS/开机自检 1

【SQL】ROW_NUMBER() OVER(partition by 分组列 order by 排序列)用法详解+经典实例

原文:[SQL]ROW_NUMBER() OVER(partition by 分组列 order by 排序列)用法详解+经典实例 #用法说明 select row_number() over(partition by A order by B ) as rowIndex from table A :为分组字段 B:为分组后的排序字段. table 表的结构 多为:  多人 多条的相关数据.(比如:订单信息) 此条sql语句,多用于对数据进行分组排序,并对每个组中的数据分别进行编号,编号从1开始

高斯消元法(Gauss Elimination)【超详解&amp;模板】

高斯消元法,是线性代数中的一个算法,可用来求解线性方程组,并可以求出矩阵的秩,以及求出可逆方阵的逆矩阵.高斯消元法的原理是:若用初等行变换将增广矩阵 化为 ,则AX = B与CX = D是同解方程组. 所以我们可以用初等行变换把增广矩阵转换为行阶梯阵,然后回代求出方程的解. 1.线性方程组 1)构造增广矩阵,即系数矩阵A增加上常数向量b(A|b) 2)通过以交换行.某行乘以非负常数和两行相加这三种初等变化将原系统转化为更简单的三角形式(triangular form) 注:这里的初等变化可以通过

海量数据处理算法总结【超详解】

1. Bloom Filter [Bloom Filter]Bloom Filter(BF)是一种空间效率很高的随机数据结构,它利用位数组很简洁地表示一个集合,并能判断一个元素是否属于这个集合.它是一个判断元素是否存在集合的快速的概率算法.Bloom Filter有可能会出现错误判断,但不会漏掉判断.也就是Bloom Filter判断元素不再集合,那肯定不在.如果判断元素存在集合中,有一定的概率判断错误.因此,Bloom Filter不适合那些“零错误”的应用场合. 而在能容忍低错误率的应用场合

vsftpd.conf超详解配置

1.默认配置 以下根据默认配置给出中文注释 # Example config file /etc/vsftpd/vsftpd.conf # # The default compiled in settings are fairly paranoid. This sample file # loosens things up a bit, to make the ftp daemon more usable. # Please see vsftpd.conf.5 for all compiled 

【转】VMware虚拟机三种网络模式超详解

[原文]https://www.toutiao.com/i6596228488666022403/ 由于Linux目前很热门,越来越多的人在学习Linux,但是买一台服务放家里来学习,实在是很浪费.那么如何解决这个问题?虚拟机软件是很好的选择,常用的虚拟机软件有VMware Workstations和VirtualBox等. 在使用虚拟机软件的时候,很多初学者都会遇到很多问题,而VMware的网络连接问题是大家遇到最多问题之一.在学习交流群里面,几乎每天都会有同学问到这些问题,写这篇详解也是因为

http协议详解-经典篇

本文转载至 http://www.cnblogs.com/flychen/archive/2012/11/28/2792206.html ———————————————————————————————————————— 欢迎转载,尊重原创——flychen http://www.cnblogs.com/flychen ———————————————————————————————————————— AUTHOR:  Jeffrey.zhu  引言 HTTP是一个属于应用层的面向对象的协议,由于其