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