codevs1004四子连棋[BFS 哈希]

1004 四子连棋 

时间限制: 1 s

空间限制: 128000 KB

题目等级 : 黄金 Gold

题目描述 Description

在一个4*4的棋盘上摆放了14颗棋子,其中有7颗白色棋子,7颗黑色棋子,有两个空白地带,任何一颗黑白棋子都可以向上下左右四个方向移动到相邻的空格,这叫行棋一步,黑白双方交替走棋,任意一方可以先走,如果某个时刻使得任意一种颜色的棋子形成四个一线(包括斜线),这样的状态为目标棋局。

 
 

输入描述 Input Description

从文件中读入一个4*4的初始棋局,黑棋子用B表示,白棋子用W表示,空格地带用O表示。

输出描述 Output Description

用最少的步数移动到目标棋局的步数。

样例输入 Sample Input

BWBO
WBWB
BWBW
WBWO

样例输出 Sample Output

5



很像八数码问题,状态空间搜索

保存State一个二维数组,本次选的颜色,步数,(封装一个结构体也可以),BFS就行了,每次从空白走

hash表来判重

手写队列一个好处是可以直接用队列的编号

PS:1从hzwer那里学了些命名

   2据说迭代加深也可以,感觉并不好写

//
//  main.cpp
//  codevs1004
//
//  Created by Candy on 9/29/16.
//  Copyright © 2016 Candy. All rights reserved.
//

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N=5,MAXN=1e6,MOD=155333,hashsize=2e5;
typedef int State[N][N];
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();}
    while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();}
    return x;
}
int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0},ans=-1;
char s[N];
State q[MAXN];
int head=1,tail=0,d[MAXN],col[MAXN];
bool equ(char a,char b,char c,char d){
    if(a!=b||b!=c||c!=d) return false;
    return true;
}
bool check(State &a){
    for(int i=1;i<=4;i++){
        if(equ(a[i][1],a[i][2],a[i][3],a[i][4])) return 1;
        if(equ(a[1][i],a[2][i],a[3][i],a[4][i])) return 1;
    }
    if(equ(a[1][1],a[2][2],a[3][3],a[4][4]))return 1;
    if(equ(a[1][4],a[2][3],a[3][2],a[4][1]))return 1;
    return 0;
}
bool valid(int x,int y,int num){
    if(x<1||x>4||y<1||y>4) return 0;
    if(q[num][x][y]!=col[num]) return 0;
    return 1;
}
int h[hashsize],ne[hashsize];
void init(){memset(h,0,sizeof(h));}
int gethash(State &s){
    int x=0;
    for(int i=1;i<=4;i++){
        for(int j=1;j<=4;j++) x=x*3+s[i][j];
        x%=MOD;
    }
    return x;
}
bool tti(int num){
    int x=gethash(q[num]);
    for(int i=h[x];i;i=ne[i])
        if(memcmp(q[i],q[num],sizeof(q[num]))==0) return 0;
    ne[num]=h[x];
    h[x]=num;
    return 1;
}
void move(int x,int y){
    State &s=q[head];
    for(int i=0;i<4;i++){
        int nx=x+dx[i],ny=y+dy[i];
        if(!valid(nx,ny,head)) continue;
        State &t=q[++tail];
        memcpy(t,s,sizeof(s));
        swap(t[nx][ny],t[x][y]);
        if(tti(tail)){
            d[tail]=d[head]+1;
            col[tail]=col[head]==1?2:1;
        }
        else tail--;
        if(check(t)) ans=d[tail];
    }
}
void bfs(){
    while(head<=tail){
        State &now=q[head]; //printf("head %d\n",head);
        for(int i=1;i<=4;i++)
            for(int j=1;j<=4;j++)
                if(now[i][j]==0) move(i,j);
        if(ans!=-1) return;
        head++;
    }
}
int main(int argc, const char * argv[]) {
    State &a=q[++tail],&b=q[++tail];
    for(int i=1;i<=4;i++){
        scanf("%s",s+1);
        for(int j=1;j<=4;j++){
            if(s[j]==‘B‘) a[i][j]=b[i][j]=1;
            else if(s[j]==‘W‘) a[i][j]=b[i][j]=2;
            else if(s[j]==‘O‘) a[i][j]=b[i][j]=0;
        }
    }
    col[1]=1;col[2]=2;
    bfs();
    printf("%d",ans);
    return 0;
}

  

时间: 2024-10-09 15:04:46

codevs1004四子连棋[BFS 哈希]的相关文章

【宽度优先搜索】神奇的状态压缩 CodeVs1004四子连棋

一.写在前面 其实这是一道大水题,而且还出在了数据最水的OJ上,所以实际上这题并没有什么难度.博主写这篇blog主要是想写下一个想法--状态压缩.状态压缩在记录.修改状态以及判重去重等方面有着极高的(←_←词穷了,诸位大致理解一下就好)效率.博主原本打算在blog介绍一种DP--状态压缩型动态规划,但动笔(键盘??)前,博主突然想起自己前些年写过的一道广搜题,当时在判重方面冥思苦想想出了一种类似状态压缩的方法,开心了好久,于是在此先抛砖引玉为状压DP做个铺垫. 二.题目 Description

codevs 1004 四子连棋 BFS、hash判重

004 四子连棋 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description 在一个4*4的棋盘上摆放了14颗棋子,其中有7颗白色棋子,7颗黑色棋子,有两个空白地带,任何一颗黑白棋子都可以向上下左右四个方向移动到相邻的空格,这叫行棋一步,黑白双方交替走棋,任意一方可以先走,如果某个时刻使得任意一种颜色的棋子形成四个一线(包括斜线),这样的状态为目标棋局. ● ○ ●   ○ ● ○ ● ● ○ ● ○ ○ ● ○   输入描述 Input

迭代加深搜索[codevs1004 四子连棋]

迭代加深搜索 一.算法简介 迭代加深搜索是在速度上接近广度优先搜索,空间上和深度优先搜索相当的搜索方式.由于在使用过程中引入了深度优先搜索,所以也可以当作深度优先搜索的优化方案. 迭代加深搜索适用于当搜索深度没有明确上限的情况. 例如上图的一棵搜索树,在进行深度优先搜索前先规定好这次搜索的最大深度dep,当搜索到达dep却还没搜索到结果时回溯. 之后不断加大搜索深度,重新搜索,直到找到结果为止.虽然这样搜索次数会累计很多次,但每一次搜索的范围和下一次搜索的范围相比微不足道,所以整体搜索速度不会受

【日常学习】【迭代加深搜索+哈希】codevs1004 四子连棋题解

转载请注明出处 [ametake版权所有]http://blog.csdn.net/ametake 题目描述 Description 在一个4*4的棋盘上摆放了14颗棋子,其中有7颗白色棋子,7颗黑色棋子,有两个空白地带,任何一颗黑白棋子都可以向上下左右四个方向移动到相邻的空格,这叫行棋一步,黑白双方交替走棋,任意一方可以先走,如果某个时刻使得任意一种颜色的棋子形成四个一线(包括斜线),这样的状态为目标棋局. ● ○ ●   ○ ● ○ ● ● ○ ● ○ ○ ● ○   输入描述 Input

Codevs 1004 四子连棋

1004 四子连棋 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description 在一个4*4的棋盘上摆放了14颗棋子,其中有7颗白色棋子,7颗黑色棋子,有两个空白地带,任何一颗黑白棋子都可以向上下左右四个方向移动到相邻的空格,这叫行棋一步,黑白双方交替走棋,任意一方可以先走,如果某个时刻使得任意一种颜色的棋子形成四个一线(包括斜线),这样的状态为目标棋局. ● ○ ●   ○ ● ○ ● ● ○ ● ○ ○ ● ○   输入描述 Input

1004 四子连棋

1004 四子连棋 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题解 题目描述 Description 在一个4*4的棋盘上摆放了14颗棋子,其中有7颗白色棋子,7颗黑色棋子,有两个空白地带,任何一颗黑白棋子都可以向上下左右四个方向移动到相邻的空格,这叫行棋一步,黑白双方交替走棋,任意一方可以先走,如果某个时刻使得任意一种颜色的棋子形成四个一线(包括斜线),这样的状态为目标棋局. ● ○ ●   ○ ● ○ ● ● ○ ● ○ ○ ● ○   输入描述 In

Codevs p1004 四子连棋

                      四子连棋 题目描述 Description 在一个4*4的棋盘上摆放了14颗棋子,其中有7颗白色棋子,7颗黑色棋子,有两个空白地带,任何一颗黑白棋子都可以向上下左右四个方向移动到相邻的空格,这叫行棋一步,黑白双方交替走棋,任意一方可以先走,如果某个时刻使得任意一种颜色的棋子形成四个一线(包括斜线),这样的状态为目标棋局. ● ○ ●   ○ ● ○ ● ● ○ ● ○ ○ ● ○   输入描述 Input Description 从文件中读入一个4*4

【Copy自某谷题解,有删改】P2346 【四子连棋】

其实这题可以直接二进制状压做,1表示黑棋,0表示白棋,另外记录下2个空点的位置就行了. 具体看代码(冗长): #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <queue> #include <set> #include <map> #include &

1004 四子连棋 未完成

1004 四子连棋 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题解 查看运行结果 题目描述 Description 在一个4*4的棋盘上摆放了14颗棋子,其中有7颗白色棋子,7颗黑色棋子,有两个空白地带,任何一颗黑白棋子都可以向上下左右四个方向移动到相邻的空格,这叫行棋一步,黑白双方交替走棋,任意一方可以先走,如果某个时刻使得任意一种颜色的棋子形成四个一线(包括斜线),这样的状态为目标棋局. ● ○ ●   ○ ● ○ ● ● ○ ● ○ ○ ● ○