个人复习:有技巧的搜索(二)

 传送门

 主要考察:记忆化搜索
 

第一问简单:直接从底向上搜索(或者自上到下也行),能到达最上面(或者最下面)就给1,不能就给0,最后扫描下低层情况。

搜索技巧:如果从一个点到另一个点,路劲一定会从上到下(从左到右),那么注意左右(上下)隐藏的关系。

第二问:根据题解从上到下搜索,查找到每个最上面点能达到的左右范围(递归+动规),想要用最少的储水点满足下面的干旱区,我们只需要从最左边开始,每次选包含当前位置的点且右边范围最大的储水点。

 

代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define Max 550
#define max(a,b) a>b?a:b;
#define min(a,b) a>b?b:a;
int a[Max][Max];
int map[Max][Max];
int left[Max][Max];
int right[Max][Max];
int n,m;
int X[]={-1,1,0,0},Y[]={0,0,-1,1};
int dfs(int y,int x)  //行、列  搜索从上到下 
{
	map[y][x]=1;//标记走过 
	int next_x,next_y;
	for(int i=0;i<4;i++)
	{
		next_x=x+X[i];
		next_y=y+Y[i];
		if(next_x>=0&&next_x<m&&next_y>=0&&next_y<n&&a[next_y][next_x]<a[y][x]) //没有出界且满足高到低 
		{
			if(!map[next_y][next_x])
			{
				dfs(next_y,next_x);
			}
			left[y][x]=min(left[y][x],left[next_y][next_x]);  //更新最左边的范围 
			right[y][x]=max(right[y][x],right[next_y][next_x]);  //更新最右边的范围 
		}
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	memset(left,0x3f,sizeof(left));
	for(int i=0;i<m;i++)
		left[n-1][i]=right[n-1][i]=i; //初始化左右范围 
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<m;j++)
		{
			scanf("%d",&a[i][j]);
		 } 
	}
	for(int i=0;i<m;i++)
	{
		if(!map[0][i]) dfs(0,i); //走过的可以不走 
	}
	int flag=0;
	int count=0;
	for(int i=0;i<m;i++)
	{
		if(!map[n-1][i]) //没有走过 
		{
			flag=1;
			count++;
		}
	}
	if(flag)
	{
		printf("0\n%d\n",count);
		return 0;
	}
	int num=0; //从最左边的点开始 
	while(num<m)
	{
		int max_r=0;
		for(int i=0;i<m;i++)
		{
			if(left[0][i]<=num) //如果包含当前点 
			{
				max_r=max(max_r,right[0][i]);  //找到最右的储水点 
			}
		}
		count++;
		num=max_r+1; //下一个点没包含进来 
	}
	printf("1\n%d\n",count);
	return 0;
}

看了题解才写出来.......题解传送门

......这题没写出来很不应该,这种情况隐约遇到过,也知道不是从上搜就是从下搜,因为我死于这种思路:

直接搜是不行的,需要记忆化,怎么记忆化才能最大化。

 

(我开始的搜索是从下往上走)

一:没有走过下个点,递归调用。

三:走过,下个点能走通。从当前点能走到水库就给当前点水库的标号(最上层之间也能用通道,可以减少水库数量),同时把干旱点保存到各个水库独自的集合,方便最后在O(m^2)时间内求解。但是其他方向也能走通,一个点有多个办法到达最上层........怎么保存,并且动态操作的复杂度小...........。

二:如果不能走通直接给-1,警示后面走到这个点,不要继续走了。

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值