zoukankan      html  css  js  c++  java
  • 棋盘(BFS)

    原题:

    棋盘(chess)

    时间限制: 1 Sec  内存限制: 256 MB

    题目描述

    有一个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, 1)开始,走到( 1, 2)不花费金币
    从( 1, 2)向下走到( 2, 2)花费 1 枚金币
    从( 2, 2)施展魔法,将( 2, 3)变为黄色,花费 2 枚金币
    从( 2, 2)走到( 2, 3)不花费金币
    从( 2, 3)走到( 3, 3)不花费金币
    从( 3, 3)走到( 3, 4)花费 1 枚金币
    从( 3, 4)走到( 4, 4)花费 1 枚金币
    从( 4, 4)施展魔法,将( 4, 5)变为黄色,花费 2 枚金币,
    从( 4, 4)走到( 4, 5)不花费金币
    从( 4, 5)走到( 5, 5)花费 1 枚金币
    共花费 8 枚金币。

     

    输出

    输出一行,一个整数,表示花费的金币的最小值,如果无法到达,输出-1。
     
    样例2输入

    5 5

    1 1 0

    1 2 0

    2 2 1

    3 3 1

    5 5 0

    样例2输出:

    -1

    输入输出样例 2 说明
    从( 1, 1)走到( 1, 2),不花费金币
    从( 1, 2)走到( 2, 2),花费 1 金币
    施展魔法将( 2, 3)变为黄色,并从( 2, 2)走到( 2, 3)花费 2 金币
    从( 2, 3)走到( 3, 3)不花费金币
    从( 3, 3)只能施展魔法到达( 3, 2),( 2, 3),( 3, 4),( 4, 3)
    而从以上四点均无法到达( 5, 5),故无法到达终点,输出-1

    样例输入

    5 7

    1 1 0

    1 2 0

    2 2 1

    3 3 1

    3 4 0

    4 4 1

    5 5 0

    样例输出

    8

    数据范围

    对于 30%的数据, 1 ≤ m ≤ 5, 1 ≤ n ≤ 10。
    对于 60%的数据, 1 ≤ m ≤ 20, 1 ≤ n ≤ 200。
    对于 100%的数据, 1 ≤ m ≤ 100, 1 ≤ n ≤ 1,000。
     
     

        本蒟蒻第一次写题解,写的不好多多包涵
        这是一道很明显的搜索题,最近几天在练BFS的题目,所以讲讲BFS解题思路,大佬勿喷
    题意:
      在一个m*m的棋盘中,从(1,1)出发到(m,m),上下左右移动,移动到同色格子不需要代价,移动到不同色格子需要代价为1,不能移动到无色格子但可以花费代价2将无色格子变为有色格子,不能从无色格子移动到另一无色格子

    首先考虑从一个格子走到另一个格子有哪些情况
    (方便起见将红色设为1,黄色设为2,无色设为0):

    1. 从有色格子走到同一有色格子(1->1或2->2)
    2. 从有色格子走到不同色的有色格子(1->2或2->1)
    3. 从有色格子走到无色格子(此时需要使用魔法)(1->0或2->0)
    4. 从施了魔法的无色格子移动到有色格子(还需考虑魔法将无色格子变成了什么颜色)(0->1或0->2)

     



    接着考虑搜索到一个可走的点时需要将哪些元素压入队列,用一个结构体捆绑

    1 struct node
    2 {
    3 int x,y,c,s,p;
    4 }now;

    其中x,y表示加入队列的点的坐标(x,y),c记录该点原本的颜色,s记录该点施了魔法后的颜色(若该点原本有色则s仍为原本的颜色),p记录目前所需的代价。

    因为本题需要的是代价最小而不是步数,所以最先搜索到的点不一定是代价最小的点,再建一个v数组统计所有可能的代价。

    套入BFS的模板,代码如下:

     1 #include<iostream>
     2 #include<stdio.h>
     3 #include<queue>
     4 using namespace std;
     5 int n,m,ans,tot,mark[1005][1005],map[1005][1005],v[5005];
     6 //tot统计所有可能的代价
     7 //mark记录到各个点的最小代价
     8 //map记录棋盘初始状况
     9 //v记录到达终点的所有可能的代价 
    10 int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
    11 //用dx,dy两个数组控制移动方向 
    12 struct node
    13 {
    14     int x,y,c,s,p;
    15 }now;
    16 queue<node> q;//STL库自带的队列
    17 //听说速度会比手打队列慢一点,但应该关系不大 
    18 void bfs(int x,int y)
    19 {
    20     mark[x][y]=0;//起点不需要代价 
    21     q.push({x,y,map[x][y],map[x][y],0});
    22     while(!q.empty()) 
    23     {
    24         now=q.front();
    25         q.pop();//出队 
    26         x=now.x,y=now.y;
    27         int c=now.c,p=now.p,s=now.s;
    28         if(x==m && y==m)  v[++tot]=p;//找到一个解就存入v数组 
    29         for(int i=0;i<4;i++)
    30         {
    31             int tx=x+dx[i],ty=y+dy[i];
    32             if(tx>=1 && tx<=m && ty>=1 && ty<=m)
    33             {//判断是否越界 
    34                 if(map[x][y]!=0 && map[x][y]==map[tx][ty] && mark[tx][ty]>p)
    35                 {
    36                     mark[tx][ty]=p;//如果可以得到更小代价就更新,下同 
    37                     q.push({tx,ty,map[tx][ty],map[tx][ty],p});//入队 
    38                 }
    39                 //第一种情况 
    40                 else  if(map[x][y]!=0 && map[tx][ty]!=0 && map[x][y]!=map[tx][ty] && mark[tx][ty]>p+1)
    41                 {
    42                     mark[tx][ty]=p+1;
    43                     q.push({tx,ty,map[tx][ty],map[tx][ty],p+1});
    44                 }
    45                 //第二种情况 
    46                 else  if(map[x][y]!=0 && map[tx][ty]==0 && mark[tx][ty]>p+2)
    47                 {
    48                     mark[tx][ty]=p+2;
    49                     q.push({tx,ty,map[tx][ty],map[x][y],p+2});
    50                     //注意,这种情况需要使用一次魔法,此时s记录为未移动前的格子的颜色 
    51                 }
    52                 //第三种情况 
    53                 else  if(map[x][y]==0 && map[tx][ty]==s && mark[tx][ty]>p)
    54                 {
    55                     mark[tx][ty]=p;
    56                     q.push({tx,ty,mark[tx][ty],mark[tx][ty],p});
    57                 }
    58                 //第四种情况(1) 
    59                 else  if(map[x][y]==0 && map[tx][ty] && map[tx][ty]!=s && mark[tx][ty]>p+1)
    60                 {
    61                     mark[tx][ty]=p+1;
    62                     q.push({tx,ty,mark[tx][ty],mark[tx][ty],p+1});
    63                 }
    64                 //第四种情况(2) 
    65                 //如果这几种情况都不符合,只剩下从无色格子到无色格子一种可能,不需考虑 
    66             }
    67         }
    68     }
    69 return;
    70 }
    71 int main()
    72 {
    73     scanf("%d %d",&m,&n);
    74     for(int i=1;i<=m;i++)
    75         for(int j=1;j<=m;j++)  mark[i][j]=0x7fffffff;
    76     //将到达各个点的最小代价初始化为无穷大(0x7fffffff) 
    77     for(int i=1;i<=n;i++)
    78     {
    79         int a,b,cl; 
    80         scanf("%d %d %d",&a,&b,&cl);
    81         map[a][b]=cl+1;//将红色记为1,黄色记为2,无色则为0 
    82     }
    83     bfs(1,1);
    84     if(!tot)  { printf("-1"); return 0; }//如果没有解,输出-1 
    85     ans=v[1];
    86     for(int i=2;i<=tot;i++)  ans=min(ans,v[i]);
    87     //比较并求出最小代价 
    88     printf("%d",ans);
    89 return 0;
    90 }

     嘿,来都来了,不点个赞再走吗?

  • 相关阅读:
    深入理解JavaScript闭包
    冒泡排序
    Objective-C中的self和super
    IOS中UIKit——UIButton的背景图像无法正常显示的原因
    IOS绘图——简单三角形
    NSDateFormatter中时间格式串的含义
    IOS屏幕布局
    IOS学习感想
    WWDC————苹果全球开发者大会
    刚开始学IOS遇到的类和方法
  • 原文地址:https://www.cnblogs.com/leaf-2234/p/13307471.html
Copyright © 2011-2022 走看看