[刷题之旅no26]P3956 [NOIP2017 普及组] 棋盘

1.走棋盘
同色直接走
异色花一金
无色可魔法
魔法花两金
不可连续魔
要求最小金
不通为负一
思路:
1.用深搜,设置参数,四个,坐标xy,是否可以使用魔法,当前金币数量
根据当前位置判断可以走的方向,然后根据情况递归即可。
问题:
1.如何确定施加魔法的颜色
2.如何执行施加魔法之后颜色消失这一步。
3.如何防止重复绕圈,也就是如果我按照当前位置四个方向进行递归,肯定会出现重复路线
解决问题:
3.每次进入函数,将当前坐标相应位置标记为1.
然后递归。
当递归结束之后,把相应位置标记为0;
return;
//递归棋盘的标准方法
1.如何确定施加魔法的颜色
实际上,我们不用确定到底施加什么颜色
如果当前位置四周出现空位置,
那么在我们递归这个空位置时,再判断四周情况
如果还是空位置,那就无法继续递归了
如果有红色,那么就当作我们施加了红色魔法,不花钱直接进入
如果有黄色,那么就当作我们施加了黄色魔法,不花钱直接进入
这样随机颜色,顺便把我们的2问题也解决掉了。嘻嘻
预处理:我比较喜欢初始化数组为0,那么就和题目中要求的红为0冲突,所以我把题目中的红色改成2
然后把数组开大一点,设置城墙为3,防止出现越界问题
递归函数细则:
1.标记当前点
如果当前点==m,m即到达终点
那么和最小gold进行比较,如果比最小gold小,更新
并且把当前点清0。
return;
遍历四周点:
分别判断以下情况
4.城墙或者已经走过了
不可以递归
1.空的
看当前是否可以使用魔法
能则递归,金币加2,magic改成0“不可使用”
2.红色
判断当前是否可以使用魔法

看当前方方块颜色
红色,直接走,金币不变,magic不变
黄色,直接走,金币加1,magic不变
不能
说明当前这个方块就是我用魔法变来的
所以我选红色
直接递归,金币不变,magic改成1
3.黄色
和红色同理
城墙和已经走过了放在最前面,因为这是不符合的情况
如果四周点都递归完成
取消标记当前点
return即可;
好的,目前出现了一个小逻辑错误
测试样例中的8我打印出来7
现在需要测试寻找问题
逻辑出现问题
也就是说
如果我当前所在位置为黄色
隔着一块空地为红色
如果按照我原来的思路
将其随机
那么如果是红色
我需要花费2+1
如果是黄色
我也需要2+1;
而我想的是,只花费2
新思路解决2.3问题
如果可以施加魔法
保证施加魔法所出现的颜色和当前所站位置颜色相等。
这样可以保证花金币最少
递归,金币+2;
递归结束之后,把这一块颜色归0即可
改变这个逻辑思路,其它都要改变
比如
遍历四周遇到红色:
1.如果当前可以使用魔法
那么判断当前位置颜色
红色,直接走,magic=1;
黄色,金币+1,magic=1;
2.如果不可以使用魔法
判断当前位置
红色,直接走,magic=1;
黄色,金币+1,magic=1;
前后一样,故合并
啊偶
深搜TLE了,不过思路没问题,我还是很高兴的
我咋感觉是出现了死递归问题呢?程序输入之后一直没结果,我需要检查一下了
感觉题目一直在搜索一些没有意义的坐标
分支不会多到数不过来啊!
看题解里面也有人使用dfs方法,到底是怎么回事导致我的递归死亡了呢
学习一下大佬的思想吧,还是不太明白到底为什么会递归那么多次
突然想起来,在基数非常大的时候,递归的次数上升会非常快
此时如果想要优化dfs,则需要用到记忆化搜索。
记忆化搜索,是我之前的遗留问题,现在还是要解决掉啊!
设置一个数组,记录1,1到x,y的最优解f[x,y]
也就是gold最小值,如果当前的递归的值大于此值,那么就可以直接滚蛋了,就不用再递归下去了。
这样可以大大节省时间
ok,相当完美,过了。也不是啥难题,就是dfs的优化!!!!

#include<stdio.h>
typedef struct
{
	int dx,dy;
}a;
a move[4]={{-1,0},{1,0},{0,-1},{0,1}};//上下左右 
int maze[102][102]={0},tag[102][102]={0},mingold[102][102],m=0,n=0,x,y,color,find=0;
void dfs(int x,int y,int gold,int magic);
int main()
{
	//读取
	scanf("%d %d",&m,&n);
	//涂色 
	for(int i=1;i<=n;i++)
	{
		scanf("%d %d %d",&x,&y,&color);
		if(color==0)
		{
			maze[x][y]=2;//2为红色 
		}
		else
		{
			maze[x][y]=1;//黄色 
		}
	}
	//加城墙
	for(int i=0;i<=m+1;i++)
	{
		maze[0][i]=3;
		maze[i][0]=3;
		maze[m+1][i]=3;
		maze[i][m+1]=3;//3当城墙 
	}
	//预处理mingold,将所有元素都调成最大值
	for(int i=0;i<=m+1;i++)
	{
		for(int j=0;j<=m+1;j++)
		{
			mingold[i][j]=0xffff;
		}
	}
	dfs(1,1,0,1);
	if(find)
	{
		printf("%d",mingold[m][m]);
	}
	else
	{
		printf("-1");
	}
}

void dfs(int x,int y,int gold,int magic)
{
	tag[x][y]=1;
	//利用mingold减少递归次数
	if(gold<mingold[x][y])
	{
		mingold[x][y]=gold;//更新最小值
		if(x==m&&y==m)
		{
			find=1;
			tag[x][y]=0;
			return ;
		}
	}
	else
	{
		tag[x][y]=0;
		return ;//如果不是最小的,那么我还有什么意义去走你呢? 
	}
	int nx,ny; 
	for(int i=0;i<4;i++)//遍历四周
	{
		nx=x+move[i].dx;
		ny=y+move[i].dy;
		if(tag[nx][ny]==1||maze[nx][ny]==3)
		{
			continue;
		}
		else if(maze[nx][ny]==0)
		{
			if(magic)//如果可以使用魔法
			{
				maze[nx][ny]=maze[x][y];
//				printf("x=%d,y=%d,gold=%d\n",nx,ny,gold);
				dfs(nx,ny,gold+2,0);
				maze[nx][ny]=0;
			}
		}
		else if(maze[nx][ny]==2)
		{
			if(maze[x][y]==2)
			{
//				printf("x=%d,y=%d,gold=%d\n",nx,ny,gold);
				dfs(nx,ny,gold,1);
			}
			else if(maze[x][y]==1)
			{
//				printf("x=%d,y=%d,gold=%d\n",nx,ny,gold);
				dfs(nx,ny,gold+1,1);
			}
		}
		else if(maze[nx][ny]==1)
		{
			if(maze[x][y]==1)
			{
//				printf("x=%d,y=%d,gold=%d\n",nx,ny,gold);
				dfs(nx,ny,gold,1);
			}
			else if(maze[x][y]==2)
			{
//				printf("x=%d,y=%d,gold=%d\n",nx,ny,gold);
				dfs(nx,ny,gold+1,1);
			}
		}
	}
	tag[x][y]=0;
	return ;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你好!感谢你的提问。根据你的要求,我将为你解答关于NOIP2017普及t3问题的内容。 在这道题目中,我们需要解决一个关于棋盘的问题。题目描述了一个n×m的棋盘,每个格子上有一个非负整数。开始时,小明站在左上角的格子上,他可以向右或向下移动一步,每次移动的代价为目标格子上的数值。我们需要找到一条从左上角到右下角的路径,使得移动的总代价最小。 解决这个问题的一个常见的方法是使用动态规划(Dynamic Programming)。我们可以创建一个二维数dp,其中dp[i][j]表示从起点到达坐标为(i, j)的格子时的最小代价。然后,我们可以按照从左上角到右下角的顺序依次计算dp数的值。 具体的计算方法如下: 1. 首先,我们可以初始化dp数的第一行和第一列,即dp[0][j]和dp[i][0],它们表示从起点到达第一行和第一列的格子时的最小代价。初始化的方法是累加前面的格子的代价。 2. 接下来,我们可以使用一个双重循环,从(1, 1)开始遍历整个棋盘。对于每个格子(i, j),我们可以选择从上方格子(i-1, j)或左方格子(i, j-1)中选择一个代价较小的路径,并加上当前格子的代价。即dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j]。 3. 最后,当我们计算完dp数的所有值后,dp[n-1][m-1]即为从起点到达右下角的格子时的最小代价。 这样,我们就可以得到从左上角到右下角的最小代价。希望能对你的问题有所帮助!如果你还有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值