#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <queue>
#include <cstring>
#include <map>
#include <set>
using namespace std; const int maxn = ;
//可移动方向
int dir[][] = { { -, }, { , }, { , }, { , - } };
struct Status {
//last = 1 : 黑子, last = 2 : 白子
//包括把16位3进制转换成一个十进制数的结果hash,移动步数step
int hash, step, last; //hash:为了描述棋子的位置信息,但是不能重复
int map[maxn][maxn];
} Map; /*
* h[1][x]记录黑子放的移动到达的信息
* h[1][x]=false,表示还没有移动这个状态
* h[1][x]=true, 表示之前已经到达过, 不用进队
*/
map<int, bool> h[];
queue<Status> que; //BFS, 队列 void input(); //输入数据
void solve(); //启动函数
bool judge(int r, int c); //判断越界
bool check(Status a); //判断是否满足目标状态
//移动一步,生成新的棋子位置, k 为移动方向
void Move(Status now, int r, int c, int k);
void findSpace(const Status& now, int &r, int &c, int &r2, int &c2); //找到空格的位置
//把此时棋盘的状态, 全部用0,1,2表示每一位的三进制,转换成一个十进制
int getHash(Status a); //对当前棋盘的棋子设置HashCode
void BFS(); //宽搜BFS void input()
{
char s[];
/*
* 把每一位的棋子 换成 空格-0,黑子-1, 白子-2 (三进制)
* 这是一个16位的3进制数, 对应一个十进制数, 然后通过哈希该
* 棋盘的十进制数, 则可找到对应的棋盘状态
*/
for (int i = ; i < maxn; i++)
{
scanf("%s", s);
for (int j = ; j < maxn; j++) {
if (s[j] == 'B') Map.map[i][j] = ;
if (s[j] == 'W') Map.map[i][j] = ;
}
}
} bool judge(int r, int c)
{
return (r >= && r < maxn) && (c >= && c < maxn);
} bool check(Status a)
{
bool flag = true;
//横向连成4个
for (int i = ; i < maxn; i++)
{
flag = true;
for (int j = ; j < maxn - ; j++) {
if (a.map[i][j] != a.map[i][j + ]) {
flag = false;
}
}
if (flag) return true;
} //纵向连成4个
for (int i = ; i < maxn; i++)
{
flag = true;
for (int j = ; j < maxn - ; j++) {
if (a.map[j][i] != a.map[j + ][i]) {
flag = false;
}
}
if (flag) return true;
} flag = true;
for (int i = ; i < maxn - ; i++) {
if (a.map[i][i] != a.map[i + ][i + ]) {
flag = false;
}
}
if (flag) return true; flag = true;
for (int i = maxn - ; i > ; i--) {
if (a.map[i][i] != a.map[i - ][i - ]) {
flag = false;
}
}
if (flag) return true; //都没有连成4子, false
return false;
} //全部用0,1,2表示每一位的三进制,转换成一个十进制
//用了Hash查找
int getHash(Status a)
{
int res = ;
int k = ;
for (int i = ; i < ; i++) {
for (int j = ; j < ; j++) {
res += a.map[i][j] * k;
k *= ;
}
}
return res;
} void findSpace(const Status& now, int &r1, int &c1, int &r2, int &c2)
{
for (int i = ; i < maxn; i++)
{
for (int j = ; j < maxn; j++) {
if (!now.map[i][j])
{
if (r1 == - && c1 == -) {
r1 = i; c1 = j;
}
else {
r2 = i; c2 = j;
}
}
}
}
} /*每移动 一步,都需要对其进行
* 1.是否越界检查
* 2.移动棋子, 并标志移动, 并设置下一次移动的棋子种类
* 3.是否完成目标检查
* 4.未完成 则 设置新棋盘的HashCode
* 5.检查该棋子状态 是否出现过, 没有则入队,并标志为出现过
*移动一步,生成新的棋子位置, k 为移动方向
*/
void Move(Status now, int r, int c, int k)
{
Status tmp = now;
int tmpx = r + dir[k][];
int tmpy = c + dir[k][];
//判断是否越界 || 先后手, 不能两次都移动自己的子
//(如,第一次移动白子,第二次,白子能够移动还移动白子,是错误行为
if (!judge(tmpx, tmpy) || tmp.map[tmpx][tmpy] == tmp.last)
return;
tmp.last = - tmp.last; //取反,上次白子(1), 这次就黑子(2)
swap(tmp.map[tmpx][tmpy], tmp.map[r][c]); //交换棋子和空白位置
tmp.hash = getHash(tmp); //重新设置hashCode
tmp.step++; //移动成功,步数+1
if (check(tmp)) {
printf("%d\n", tmp.step);
exit(); //结束整个程序
}
//表示tmp.last这个种类, 单独的某个棋子 当前的状态-是否移动过
//false-没有移动过,可以入队
if (!h[tmp.last][tmp.hash])
{
h[tmp.last][tmp.hash] = true; //标志此状态已经出现过
que.push(tmp); //入队
}
} void BFS()
{
Map.hash = getHash(Map); //首状态棋盘对应的HashCode
//因为谁先下都行,所以两个棋子都应该入队
Map.last = ;
que.push(Map);
Map.last = ; //黑
que.push(Map); while (!que.empty())
{
Status now;
now = que.front();
que.pop();
int r1 = -, c1 = -, r2 = -, c2 = -;
findSpace(now, r1, c1, r2, c2); //找到空格位置 //一个棋盘有两个空格,所以两个一起来搜索四个方向
for (int k = ; k < maxn; k++) {
Move(now, r1, c1, k);
Move(now, r2, c2, k);
}
}
} void solve()
{
input();
BFS();
} int main()
{
solve();
return ;
}

BFS算法不错的练习~

参考了这篇博客: http://blog.csdn.net/re_cover/article/details/9034219

BFS搜索算法应用_Codevs 1004 四子连棋的更多相关文章

  1. codevs 1004 四子连棋

    1004 四子连棋  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold     题目描述 Description 在一个4*4的棋盘上摆放了14颗棋子,其中有7颗白 ...

  2. codevs 1004 四子连棋 BFS、hash判重

    004 四子连棋 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold       题目描述 Description 在一个4*4的棋盘上摆放了14颗棋子,其中有7颗白色棋 ...

  3. 【wikioi】1004 四子连棋

    题目链接 算法:BFS //2014-02-05更新 *******************************2013-10-15******************************* ...

  4. CODEVS 1004四子连棋

    [题目描述 Description] 在一个4*4的棋盘上摆放了14颗棋子,其中有7颗白色棋子,7颗黑色棋子,有两个空白地带,任何一颗黑白棋子都可以向上下左右四个方向移动到相邻的空格,这叫行棋一步,黑 ...

  5. CODEVS——T 1004 四子连棋

    http://codevs.cn/problem/1004/  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题解  查看运行结果     题目描述 Descr ...

  6. codevs1004四子连棋[BFS 哈希]

    1004 四子连棋   时间限制: 1 s   空间限制: 128000 KB   题目等级 : 黄金 Gold   题目描述 Description 在一个4*4的棋盘上摆放了14颗棋子,其中有7颗 ...

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

    一.写在前面 其实这是一道大水题,而且还出在了数据最水的OJ上,所以实际上这题并没有什么难度.博主写这篇blog主要是想写下一个想法--状态压缩.状态压缩在记录.修改状态以及判重去重等方面有着极高的( ...

  8. codevs1004四子连棋

    1004 四子连棋  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold     题目描述 Description 在一个4*4的棋盘上摆放了14颗棋子,其中有7颗白 ...

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

    迭代加深搜索 一.算法简介 迭代加深搜索是在速度上接近广度优先搜索,空间上和深度优先搜索相当的搜索方式.由于在使用过程中引入了深度优先搜索,所以也可以当作深度优先搜索的优化方案. 迭代加深搜索适用于当 ...

随机推荐

  1. Activity猫的一生-故事解说Activity生命周期

    大家好,关于Android中Activity的生命周期,网上大多数文章基本都是直接贴图.翻译API,比较笼统含糊不清. 我就用故事来说一说: 有个人叫User,TA养了几只猫,有只猫叫Activity ...

  2. tensorflow 曲线拟合

    tensorflow 曲线拟合 Python代码: import numpy as np import tensorflow as tf import matplotlib.pyplot as plt ...

  3. JavaWeb项目学习教程(1) 准备阶段

    写在最前面 为什么要写一个这样的教程?作为一个软件工程专业的学生,上课老师讲得飞快,几乎都是在课后自己消化,我知道学习记录的重要性.我自己本身还有很多很多基础的东西都没有学会,比较博客园的人有很大的差 ...

  4. CentOS Docker环境搭建教程

    安装与配置 Docker 安装 Docker Docker 软件包已经包括在默认的 CentOS-Extras 软件源里.因此想要安装 docker,只需要运行下面的 yum 命令: yum inst ...

  5. [!] CocoaPods could not find compatible versions for pod "Folly"问题举例

    $ pod install 后出现下面错误: [!] CocoaPods could not find compatible versions for pod "Folly": I ...

  6. 《Linux内核分析》第三周学习笔记

    <Linux内核分析>第三周学习笔记 构造一个简单的Linux系统MenuOS 郭垚 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.stud ...

  7. day5——Java 实现导出excel表 POI(转)

    1.首先下载poi-3.6-20091214.jar,下载地址如下: http://download.csdn.net/detail/evangel_z/3895051 2.Student.java ...

  8. 【JavaService】使用Java编写部署windows服务

    如果你玩windows系统,你对服务这个东西并不会陌生,服务可以帮我们做很多事情,在不影响用户正常工作的情况下,可以完成很多我们需要的需求. 众所周知,微软的visio studio内置的Servic ...

  9. Entity Framework(EF) Code First将实体中的string属性映射成text类型的几种方式

    1.通过ColumnType属性设置 [Column(TypeName="text")] public string Text { get; set; } 在进行以上属性设置时,请 ...

  10. JDK8新特性,给接口添加一个默认实现

    在JDK8中,允许给接口本身添加一个默认的实现.用“default”进行修饰.如下实例 package interfacetest; public interface TestInterface { ...