记忆化深度优先搜索(MDFS)
宏观思路:我们从左上角一直走到右下角,dp[x][y]表示所有走到(x,y)这个格子的所有路中,所需代价最小的值。
for(int i=1;i<=m;i++)
for(int j=1;j<=m;j++)
{
g[i][j]=-1; //先把所有格子都置为-1
dp[i][j]=0x3f3f3f3f; //先赋一个很大的值
}
for(int i=1;i<=n;i++)
{
int x,y,c;
cin>>x>>y>>c;
g[x][y]=c;
}
//按题目所说,表示坐标为(x,y)(x,y)的格子有颜色c
dp[1][1]=0;//左上角第一个格子设为0,这样才能推下去
dfs(1,1,1);//从(1,1)开始深搜
if(dp[m][m]!=0x3f3f3f3f) cout<<dp[m][m];
else cout<<"-1";
return 0;
接下来我们来看一下深搜主体
其实就是按位移增量向四个方向探索,然后判断是否是合法格局(行、列都在1~m之中)。如果当前格子不是-1(这表示它是有颜色的),再判断它是否跟上一个格子颜色相同,如果相同,就搜索下去(中间要剪枝),如果是不相同的颜色,就要花费1个金币。如果一开始当前格子是-1,那么判断是否可以使用魔法。
void dfs(int x,int y,bool f)
// x,y为行号列号;如果f为假,则当前不可使用魔法,如果为真,可以使用。
if(x==m&&y==m)//如果行号列号都等于m,表示已经全部走完
{
dp[x][y]=min(dp[x][y],cnt);
return;
}
//dp[x][y]里存的是之前所有路中到(x,y)的最小值,cnt为当前值,然后比一下min。
else
{
dp[x][y]=min(dp[x][y],cnt);
for(int i=0;i<4;i++)//位移增量,无需解释
{
int nx=x+dx[i];//探索出新的点
int ny=y+dy[i];
if(nx>0&&nx<=m &&ny>0&&ny<=m)//判断是否是合法格局
{
if(g[nx][ny]!=-1)//有颜色
{
if(g[x][y]==g[nx][ny])
{
if(cnt<dp[nx][ny])//剪枝,如果cnt已经大于dp[nx][ny],没有继续搜索的必要
dfs(nx,ny,1);
}
下面贴一下完整代码
//洛谷3956
#include <bits/stdc++.h>
using namespace std;
const int MAXM=100+5;
int dx[4]={0,0,-1,1};
int dy[4]={1,-1,0,0};
int n,m,cnt;
int g[MAXM][MAXM];
int dp[MAXM][MAXM];
void dfs(int x,int y,bool f)
{
if(x==m&&y==m)
{
dp[x][y]=min(dp[x][y],cnt);
return;
}
else
{
dp[x][y]=min(dp[x][y],cnt);
for(int i=0;i<4;i++)
{
int nx=x+dx[i];
int ny=y+dy[i];
if(nx>0&&nx<=m &&ny>0&&ny<=m)
{
if(g[nx][ny]!=-1)
{
if(g[x][y]==g[nx][ny])
{
if(cnt<dp[nx][ny])
dfs(nx,ny,1);
}
else
{
if(cnt+1<dp[nx][ny])
{
cnt+=1;
dfs(nx,ny,1);
cnt-=1;
}
}
}
else
{
if(f)
if(cnt+2<dp[nx][ny])
{
cnt+=2;
g[nx][ny]=g[x][y];
dfs(nx,ny,0);
g[nx][ny]=-1;
cnt-=2;
}
}
}
}
}
}
int main()
{
cin>>m>>n;
for(int i=1;i<=m;i++)
for(int j=1;j<=m;j++)
{
g[i][j]=-1;
dp[i][j]=0x3f3f3f3f;
}
for(int i=1;i<=n;i++)
{
int x,y,c;
cin>>x>>y>>c;
g[x][y]=c;
}
dp[1][1]=0;
dfs(1,1,1);
if(dp[m][m]!=0x3f3f3f3f) cout<<dp[m][m];
else cout<<"-1";
return 0;
}
本人是新手,写得比较菜
如有问题,还望指正!!