zoukankan      html  css  js  c++  java
  • goj 扫雷(dfs)

    Problem Description:

    扫雷这个游戏想必各位都是会玩的吧。简单说一下规则,n行m列的格子地图上有分布一些雷。起先每个格子
    都是未点开的状态,我们依次点开格子,找出所有雷。有如下3条规则:
    1.点开的地方如果相邻的格子(上、下、左、右,左上、左下、右上、右下)有雷,该格子显示一个数字,表
    示该格子相邻的地方有几个雷(最多8)。
    2.如果点开的地方是雷,则游戏结束。
    3.如果点开的地方和相邻的地方都没雷,就自动向外扩张到相邻有雷的地方。
    ps:没玩过扫雷不能理解上面说的可以开一下系统自带扫雷试试。不过我觉得我语言表达能力还是可以的,
    你们应该能看懂。
    给出一副n行m列的地图,'*'号表示雷。'.'表示非雷。
    写一个程序找出,最少需要点几下就能找出所有的雷。

    Input:

    输入包含多组测试,每组测试是一个n行m列的地图(0<n,m<=100),地图只包含'*'或'.'。

    Output:

    对于每组测试,输出最少需要点几下就能找出所有的雷。

    Sample Input:

    5 5
    ...**
    **.**
    *****
    .....
    *.*.*

    Sample Output:

    11
    解题思路:算是对扫雷的规则有了深刻的认识,典型的dfs。思路:如果点击的某个位置(x,y)是空白并且周围(八个方向)都没有雷,那么就会沿着周围按这个规则递归扩展空白,扩展过程中若遇到某个周围有雷的位置,则不再递归扩展,直接显示出该位置上的数字即可。于是我们先dfs扩展那些能扩展的位置,然后再单独点一下剩下那些有数字的位置即可。显然,这样的点击次数是最少的。
    AC代码:
     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long LL;
     4 const int maxn=105;
     5 int n,m,ans,dir[8][2]={{-1,-1},{-1,1},{1,-1},{1,1},{-1,0},{1,0},{0,-1},{0,1}};
     6 char mp[maxn][maxn];bool vis[maxn][maxn];
     7 bool is_border(int x,int y){///判断是否越界
     8     if(x>=0&&x<n&&y>=0&&y<m)return true;
     9     return false;
    10 }
    11 bool check(int x,int y){///检查点(x,y)周围是否都不是雷
    12     for(int i=0;i<8;++i){
    13         int nx=x+dir[i][0],ny=y+dir[i][1];
    14         if(is_border(nx,ny)&&mp[nx][ny]=='*')return false;
    15     }
    16     return true;
    17 }
    18 void dfs(int x,int y){///不必考虑mp[x][y]=='*',因为递归前已都将是雷的排除在外,但是已经访问的要返回,减少递归次数
    19     if(vis[x][y])return;///已访问则直接返回
    20     vis[x][y]=true;
    21     for(int i=0;i<8;++i){
    22         int nx=x+dir[i][0],ny=y+dir[i][1];
    23         if(is_border(nx,ny)&&!vis[nx][ny]&&mp[nx][ny]=='.'){
    24             if(check(nx,ny))dfs(nx,ny);///周围没有雷,则继续dfs扩展能到达的地方
    25             else vis[nx][ny]=true;///否则直接标记为T,表示最多只能扩充到当前位置
    26         }
    27     }
    28 }
    29 int main(){
    30     while(~scanf("%d%d",&n,&m)){
    31         memset(vis,false,sizeof(vis));ans=0;
    32         for(int i=0;i<n;++i)scanf("%s",mp[i]);
    33         for(int i=0;i<n;++i)
    34             for(int j=0;j<m;++j)
    35                 if(!vis[i][j]&&mp[i][j]=='.'&&check(i,j))dfs(i,j),ans++;///先递归扩展空白处
    36         for(int i=0;i<n;++i)
    37             for(int j=0;j<m;++j)
    38                 if(!vis[i][j]&&mp[i][j]=='.')ans++;///再将未访问点一下即可
    39         printf("%d
    ",ans);
    40     }
    41     return 0;
    42 }
     
  • 相关阅读:
    hibernate对应关系详解(转)
    mybatis genertor两种使用方式(文件+项目)
    YII2 union 不同数据结构时 解决方案
    Yii2 分表后 使用 union all 分页实现代码
    Beyond Compare 4.2.10手动破解
    Xshell 6+Xftp 6官方下载免费版
    Navicat Premium
    yii2的Console定时任务创建
    内嵌多个youtube视频并展现该频道所有视频列表
    video.js 动态获取URL 并播放youtube视频
  • 原文地址:https://www.cnblogs.com/acgoto/p/10047547.html
Copyright © 2011-2022 走看看