Codevs1004 四子连棋(BFS+Hash)

本文介绍了一种利用宽度优先搜索(BFS)解决五子棋问题的算法实现。通过对棋盘状态进行抽象和利用哈希表进行状态记录,实现了有效避免重复搜索并判断胜利条件的功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意分析

BFS很好想,要考虑白色先手和黑色先手两种情况。
移动棋子可以理解为移动空白部分,搜索时要注意:
1. 空白部分不能出界
2. 空白部分不能重叠
3. 移动的棋子要和当前对应要移动的棋子相同

判重的话,直接用hash就可以。
这个题hash冲突概率很低了,随便蛤蛤就可以了。

代码总览

#include<bits/stdc++.h>
using namespace std;
const int nmax = 100000;
const int INF = 0x3f3f3f3f;
const int MOD = 3733799;
const int ntx[] = {0,0,1,-1};
const int nty[] = {1,-1,0,0};
typedef struct{
    int board[4][4];
    int x[2],y[2];
    int step;
    int turn;
}status;
status now,news;
char bb[4][4];
bitset<4000000> visit;
void debug(const status & s){
    for(int i = 0;i<4;++i){
        for(int j = 0;j<4;++j){
            printf("%d ",s.board[i][j]);
        }
        if(i != 3) printf("\n");
        else printf("     %d %d\n",s.step,s.turn);
    }
    printf("\n");
}
inline bool judge(const int  & x ,const int  & y){
    if(x < 0 || x>=4 || y < 0 || y>=4) return false;
    return true;
}
inline int gethash(const status & s){
    int hh = 0,k = 1;
    for(int i = 0;i<4;++i)
        for(int j = 0;j<4;++j){
            hh = hh *3 + s.board[i][j] ;
        }
    hh %= MOD;
    return hh;
}
inline bool check(const status & s){
    int temp[3] = {0};
    for(int i = 0;i<4;++i){
        temp[0] = temp[1] = temp[2] = 0;
        for(int j = 0;j<4;++j) temp[s.board[i][j]]++;
        if(temp[1] == 4 || temp[2] == 4) return true;
        temp[0] = temp[1] = temp[2] = 0;
        for(int j = 0;j<4;++j) temp[s.board[j][i]]++;
        if(temp[1] == 4 || temp[2] == 4) return true;
    }

    temp[0] = temp[1] = temp[2] = 0;
    for(int i = 0;i<4;++i) temp[s.board[i][i]] ++;
    if(temp[1] == 4 || temp[2] ==4) return true;

    temp[0] = temp[1] = temp[2] = 0;
    for(int i = 0;i<4;++i) temp[s.board[i][3-i]] ++;
    if(temp[1] == 4 || temp[2] ==4) return true;

    return false;
}
int bfs(){
    queue<status> q; q.push(now); visit.set(gethash(now));
    now.turn = 2; q.push(now);
    while(!q.empty()){
        now = q.front(); q.pop();
        if(check(now)) {  return now.step;}
        for(int i = 0;i<2;++i){
            for(int j = 0;j<4;++j){
                news = now;
                int ox = news.x[i], oy = news.y[i];
                int nx = ox + ntx[j] , ny = oy + nty[j];
                if(judge(nx,ny) && news.board[nx][ny] != 0 ){
                    if(news.turn != news.board[nx][ny] ) { continue;}
                    swap(news.board[ox][oy],news.board[nx][ny]);
                    if(visit[gethash(news)] == 0){
                        visit.set(gethash(news));
                        news.x[i] = nx; news.y[i] = ny;
                        news.step = now.step + 1;
                        news.turn = (now.turn== 1?2:1);
                        q.push(news);
//                        debug(news);
                    }
                }
            }
        }
    }
    return -1;
}
int main(){
    visit.reset();
    bool isfirst = true;
    for(int i = 0;i<4;++i) scanf("%s",bb[i]);
    for(int i = 0;i<4;++i){
        for(int j = 0;j<4;++j){
            if(bb[i][j] == 'B') now.board[i][j] = 2;
            if(bb[i][j] == 'W') now.board[i][j] = 1;
            if(bb[i][j] == 'O') {
                now.board[i][j] = 0;
                if(isfirst) now.x[0] = i, now.y[0] = j, isfirst = false;
                else now.x[1] = i, now.y[1] = j;
            }
        }
    }
    now.step = 0;
    now.turn = 1;
    printf("%d\n",bfs());
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值