HDU5546 Ancient Go(DFS)

题意:在一个9*9的棋盘上,‘x’代表黑棋,‘o’代表白旗,‘.’代表空位置。如果一方下子能让另一方的一片连通的棋子周围没有一个空位置,即用自己的子将对方的子围起来,就能吃掉被围住的子。现在轮到黑子,问这一步能否至少吃掉一个白子。


思路:比较明显的搜索,搜索的办法也有几种,搜索空白、白子均可。最初的办法是找到一个空位置变成黑子,然后看周围有没有能被围起来的白子连通块,只要存在一个这样的连通块就行了。奈何代码太渣,不是TLE就是WA,还找不出问题TAT。。。

在不断尝试新的办法和犯了各种找不出的奇葩错误后,想出了下面的办法:

把白子作为搜索对象,每次搜索的时候统计这个连通块周围的空白位置数,小于等于1就可以被围住。访问过的位置做好标记防止重复搜索,要注意的一个问题就是一个‘.’有可能与连通块1和2都相邻,在搜索同一个连通块的时候要将访问过的‘.’做好标记,但在搜索下一个连通块的时候又要将标记清除,不然会影响后面的结果。

一个比较巧妙的处理办法就是搜索的时候给每个连通块编号,访问过的‘.’也同样编号,这样连通块之间就不会相互影响了。很大程度地避免了重复搜索,因此时间非常快,0ms就过了,还沉浸在之前代码总TLE的恐惧中T_T。。。

每次搜索总会在搜索方法上坑好久,练他个几十上百道!


//#include<bits/stdc++.h>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define INF  0x3f3f3f3f
typedef long long  LL;
char g[10][10];
int f,d[2][4]={-1,0,0,1,0,-1,1,0};
int vis[10][10],cnt;
void dfs(int x,int y,int num){//横纵坐标、连通块编号
    for(int i=0;i<4;++i){
        int dx=x+d[0][i],dy=y+d[1][i];
        if(dx>=0&&dx<9&&dy>=0&&dy<9&&vis[dx][dy]!=num){//通过编号确保了不同连通块之间不会相互影响
            vis[dx][dy]=num;
            if('.'==g[dx][dy]){
                ++cnt;
            }
            if('o'==g[dx][dy]){
                dfs(dx,dy,num);
            }
        }
    }
}
bool solve(){
    int k=1;
    for(int i=0;i<9;++i){
        for(int j=0;j<9;++j){
            if('o'==g[i][j]&&!vis[i][j]){
                cnt=0;
                vis[i][j]=true;
                dfs(i,j,k++);
                if(cnt<=1)return true;//找到解就返回结果
            }
        }
    }
    return false;
}
int main(){
    int t,k=0;
    scanf("%d",&t);
    while(t--){
        for(int i=0;i<9;++i){
            scanf("%s",g[i]);
        }
        memset(vis,0,sizeof(vis));
        printf("Case #%d: ",++k);
        if(solve()) puts("Can kill in one move!!!");
        else puts("Can not kill in one move!!!");
    }
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值