棋盘【DFS】【记搜】

题目大意:

有一个 n×n n × n 的棋盘,有2种颜色。每次你可以移到上下左右中的一格,如果这两个各自颜色相同,那么就不用花钱,如果颜色不同,将要花一块钱。这个棋盘上还有一些格子是没有颜色的,你不能站在没颜色的格子上,但是你可以花两块钱用魔法将这个格子变为任意一个颜色,但是这个魔法不能连续使用,而你离开使用了魔法的格子之后,这个格子又将变回去。求从 (1,1) ( 1 , 1 ) 走到 (n,n) ( n , n ) 的最小花费。


思路:

DFS D F S 原来可以过。。。
对于一个点 (x,y) ( x , y ) ,我们设它的最小花费为 ans[x][y] a n s [ x ] [ y ] ,那么最终答案就是 ans[n][n] a n s [ n ] [ n ]
那么就可以打一个五维的 DFS D F S dfs(x,y,use,k,c) d f s ( x , y , u s e , k , c ) 分别表示这个点的坐标为 x x y列,上一次是否使用了魔法,走到这的花费和上一个格子的颜色。
那么又要分4种情况讨论:

  • 如果这个格子没有颜色,并且上一次使用了魔法,那么就退出(不能连续两次使用魔法)。
  • 如果这个格子没有颜色,但是上一次没有使用魔法,那么就使用一次魔法,将这个格子变成与上一个格子一样的颜色(为了保证答案最优)。
  • 如果这个格子有颜色,并且和上一个格子的颜色一样,那么就不用花费走到这个格子上。
  • 如果这个格子有颜色,但是与上一个格子颜色不一样,那么就花一块钱走到这个格子上。

伪代码如下:

if ((!a[xx][yy])&&use) continue;
if ((!a[xx][yy])&&(!use)) dfs(xx,yy,1,k+2,c);
if (a[xx][yy]&&a[xx][yy]==c) dfs(xx,yy,0,k,c);
if (a[xx][yy]&&a[xx][yy]!=c) dfs(xx,yy,0,k+1,a[xx][yy]);

那么怎么处理魔法呢?
每次使用完魔法之后,花费要加2,因为为了保证答案最优,肯定是要将下一个格子的颜色变成这个各自的颜色,所以使用魔法需要两块钱,但是由于颜色一样就不用再多加一块钱。
值得注意的是,使用魔法之后并不需要真正的在数组里赋值,而是假装它是有颜色的, c c 的值不变。如果将数组a也改变了的话,程序将会很麻烦。
最终输出 ans[n][n] a n s [ n ] [ n ] 即可。


代码:

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;

const int dx[]={0,0,0,-1,1};
const int dy[]={0,-1,1,0,0};
int n,m,a[201][201],xxx,yyy,color,ans[201][201];

void dfs(int x,int y,int use,int k,int c)
{
    if (ans[x][y]<=k) return;  //剪枝,如果之前到达这里的最小花费比现在到达这里的花费要小就不继续搜
    ans[x][y]=k;  //记录最小花费
    for (int i=1;i<=4;i++)
    {
        int xx=x+dx[i];
        int yy=y+dy[i];
        if ((!a[xx][yy])&&use) continue;
        if ((!a[xx][yy])&&(!use)) dfs(xx,yy,1,k+2,c);
        if (a[xx][yy]&&a[xx][yy]==c) dfs(xx,yy,0,k,c);
        if (a[xx][yy]&&a[xx][yy]!=c) dfs(xx,yy,0,k+1,a[xx][yy]);
    }
    return;
}

int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&xxx,&yyy,&color);
        a[xxx][yyy]=color+1;
    }
    memset(ans,0x7f,sizeof(ans));   
    dfs(1,1,0,0,a[1][1]);
    if (ans[n][n]<=1e9) printf("%d\n",ans[n][n]);
     else printf("-1\n");
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值