【记忆化搜索】[NOIP-2017--普及组] -- 棋盘

【题目描述】 原题目链接地址:
  有一个m × m的棋盘,棋盘上每一个格子可能是红色、黄色或没有任何颜色的。你现在要从棋盘的最左上角走到棋盘的最右下角。
任何一个时刻,你所站在的位置必须是有颜色的(不能是无色的),你只能向上、下、左、右四个方向前进。当你从一个格子走向另一个格子时,如果两个格子的颜色相同,那你不需要花费金币;如果不同,则你需要花费 1 个金币。
  另外,你可以花费 2 个金币施展魔法让下一个无色格子暂时变为你指定的颜色。但这个魔法不能连续使用,而且这个魔法的持续时间很短,也就是说,如果你使用了这个魔法,走到了这个暂时有颜色的格子上,你就不能继续使用魔法;只有当你离开这个位置,走到一个本来就有颜色的格子上的时候,你才能继续使用这个魔法,而当你离开了这个位置(施展魔法使得变为有颜色的格子)时,这个格子恢复为无色。
  现在你要从棋盘的最左上角,走到棋盘的最右下角,求花费的最少金币是多少?
【输入格式】
  数据的第一行包含两个正整数 m,n,以一个空格分开,分别代表棋盘的大小,棋盘上 有颜色的格子的数量。
  接下来的 n 行,每行三个正整数 x,y,c,分别表示坐标为(x,y)的格子有颜色 c。其中 c=1 代表黄色,c=0 代表红色。 相邻两个数之间用一个空格隔开。 棋盘左上角的坐标为(1, 1),右下角的坐标为(m, m)。
  棋盘上其余的格子都是无色。保证棋盘的左上角,也就是(1,1)一定是有颜色的。
【输出格式】
  输出一行,一个整数,表示花费的金币的最小值,如果无法到达,输出-1。
【样例输入1】
5 7
1 1 0
1 2 0
2 2 1
3 3 1
3 4 0
4 4 1
5 5 0
【样例输出1】
8
 
图片省略~~
-------------------------------------------------------------------------------

分析:记忆化搜索, 用DP[i][j]表示走到(i,j)时的最小代价,如果当前深搜到的代价sum>=dp[i][j],直接return ; 否则更新dp[i][j]——表示这是一个更优的解,然后继续递归!与sum的判断,每一个if条件都不能省!

/*  同种颜色可以直接跳上去;/0红色,1黄色,-1空格
    跳到不同颜色花费1金币;
   op=1, 或者跳到空格-1上,开销为2,然后 再跳到有色的地方--开销1或者0;*/
-----------------------------------------------------------------------------------
 

AC题解:

  
int m,n;   //和题意描述的相反,m表示有颜色的点数,n表示正方形的边长
int G[N][N];//存贮每个格点的颜色情况!
int ans;
int dir[4][2]={ {-1,0},{1,0},{0,-1},{0,1} };

int dp[N][N];//用DP[i][j]表示走到(i,j)时的最小代价

void dfs(int x,int y,int sum,int op,int col){
   // printf("**(%d,%d) sum=%d op=%d col=%d
",x,y,sum,op,col);
    if(x==n&&y==n){
        ans=min(ans,sum);
     //   printf("________sum=%d
",sum);
        return ;
    }
    for(int i=0;i<4;i++){
        int dx=x+dir[i][0];
        int dy=y+dir[i][1];
        if(dx<1||dy<1||dx>n||dy>n)
            continue;
        if(sum>=dp[dx][dy])//进行优化,dp[][]记忆之前达到该点的最小花费!
            continue ;
        if(G[dx][dy]>=0){
            if(col==G[dx][dy]){//代价为零,同种颜色!
                dp[dx][dy]=sum;
                dfs(dx,dy,sum,0,col);
            }
            else{         //代价为1,异种颜色,可以非一次!
                dp[dx][dy]=sum+1;
                dfs(dx,dy,sum+1,0,!col);
            }
        }
        else{
            if(op==0&&dp[dx][dy]>sum+2 ){   //上面有条件:dp[dx][dy]>sum
                dp[dx][dy]=sum+2;
                dfs(dx,dy,sum+2,1,col);//op改为1表示跳到空格上了,下一步要小心!
            }

        }

    }
}

int main(){

  // freopen("checkerboard.in","r",stdin);
  // freopen("checkerboard.out","w",stdout);
    int x,y,z;
    scanf("%d%d",&n,&m);
    memset(G,-1,sizeof(G));
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&x,&y,&z);
        G[x][y]=z;//0红色,1黄色
    }
    memset(vis,0,sizeof(vis));


    ans=inf;
    memset(dp,inf,sizeof(dp));
    dp[0][0]=0;
    dfs(1,1,0,0,G[1][1]);//省时需要记忆化搜索!!

    if(ans==inf){
        printf("-1
");
    }
    else{
        printf("%d
",ans);
    }
    return 0;
}
View Code(点开有注释呦~~)
原文地址:https://www.cnblogs.com/zhazhaacmer/p/8796487.html