zoukankan      html  css  js  c++  java
  • 【记忆化搜索】[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(点开有注释呦~~)
  • 相关阅读:
    LIGGGHTS中的restart命令
    paraview计算面上的流量
    paraview计算面上的平均压力
    paraview计算区域中的平均流速
    paraview提取非常好看的流线图
    paraview显示颗粒的快捷方法
    paraview显示网格很多线条重合问题
    CFDEM中writeLiggghtsProps命令
    paraview使用ExtractCellsByRegion提取球阀阀芯中的颗粒数量
    Paraview 显示模拟时间
  • 原文地址:https://www.cnblogs.com/zhazhaacmer/p/8796487.html
Copyright © 2011-2022 走看看