其实这题可以直接二进制状压做,1表示黑棋,0表示白棋,另外记录下2个空点的位置就行了。

具体看代码(冗长):

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
#include <vector>
#include <stack>
#include <list>
#define rep(i,m,n) for(int i=m;i<=n;++i)
#define dop(i,m,n) for(int i=m;i>=n;--i)
#define lowbit(x) (x&(-x))
#define ll long long
#define INF 2147483647
#define re register
#define Open(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout);
#define Close fclose(stdin);fclose(stdout);
#define pause system("pause");
using namespace std;
inline int read(){
int s = 0, w = 1;
char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-')w = -1;ch = getchar();}
while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0',ch = getchar();
return s * w;
}
char a[6][6];
struct Node{
int x[2], y[2], s, time, who; //x,y数组记录2个空点的位置,s表示当前的状态(二进制),who表示到谁走了
}start, begin, now, tmp;
int getHash(){ //棋盘转二进制状态
int ans = 0;
rep(i, 1, 4) rep(j, 1, 4) if(a[i][j] == 'B') ans |= (1 << ( ((i - 1) << 2) + j - 1) );
return ans;
}
queue <Node> q;
bool Win(Node x){ //判赢函数
int s = x.s;
//判断有没有黑点四子连棋
if( s&1&&s&(1<<4)&&s&(1<<8)&&s&(1<<12) || s&(1<<1)&&s&(1<<5)&&s&(1<<9)&&s&(1<<13)
|| s&(1<<2)&&s&(1<<6)&&s&(1<<10)&&s&(1<<14) || s&(1<<3)&&s&(1<<7)&&s&(1<<11)&&s&(1<<15)
|| s&1&&s&(1<<1)&&s&(1<<2)&&s&(1<<3) || s&(1<<4)&&s&(1<<5)&&s&(1<<6)&&s&(1<<7)
|| s&(1<<8)&&s&(1<<9)&&s&(1<<10)&&s&(1<<11) || s&(1<<12)&&s&(1<<13)&&s&(1<<14)&&s&(1<<15)
|| s&1&&s&(1<<5)&&s&(1<<10)&&s&(1<<15) || s&(1<<3)&&s&(1<<6)&&s&(1<<9)&&s&(1<<12))
return true;
//把空点的位置赋值为1
s|=1<<(((x.x[0]-1)<<2)+x.y[0]-1); s|=1<<(((x.x[1]-1)<<2)+x.y[1]-1);
//rep(i, 1, 4){ rep(j, 1, 4) printf("%d ", (s>>(((i-1)<<2)+j-1))&1); printf("\n"); }
//判断白点有没有四子连棋
if( (s^1)&1&&(s^(1<<4))&(1<<4)&&(s^(1<<8))&(1<<8)&&(s^(1<<12))&(1<<12) || (s^(1<<1))&(1<<1)&&(s^(1<<5))&(1<<5)&&(s^(1<<9))&(1<<9)&&(s^(1<<13))&(1<<13)
|| (s^(1<<2))&(1<<2)&&(s^(1<<6))&(1<<6)&&(s^(1<<10))&(1<<10)&&(s^(1<<14))&(1<<14) || (s^(1<<3))&(1<<3)&&(s^(1<<7))&(1<<7)&&(s^(1<<11))&(1<<11)&&(s^(1<<15))&(1<<15)
|| (s^1)&&(s^(1<<1))&(1<<1)&&(s^(1<<2))&(1<<2)&&(s^(1<<3))&(1<<3) || (s^(1<<4))&(1<<4)&&(s^(1<<5))&(1<<5)&&(s^(1<<6))&(1<<6)&&(s^(1<<7))&(1<<7)
|| (s^(1<<8))&(1<<8)&&(s^(1<<9))&(1<<9)&&(s^(1<<10))&(1<<10)&&(s^(1<<11))&(1<<11) || (s^(1<<12))&(1<<12)&&(s^(1<<13))&(1<<13)&&(s^(1<<14))&(1<<14)&&(s^(1<<15))&(1<<15)
|| (s^1)&(1)&&(s^(1<<5))&(1<<5)&&(s^(1<<10))&(1<<10)&&(s^(1<<15))&(1<<15) || (s^(1<<3))&(1<<3)&&(s^(1<<6))&(1<<6)&&(s^(1<<9))&(1<<9)&&(s^(1<<12))&(1<<12))
return true;
return false;
}
int l[] = { 233, -1, 1, 0, 0 }, r[] = { 666, 0, 0, -1, 1 }, id, X, Y, kong, v[20000010];
int getHash(Node x){ //不要hack我
return x.s + x.x[0] * 10007 + x.x[1] * 107 + x.y[1] * 677 + x.y[0] * 97;
}
int main(){
rep(i, 1, 4)
rep(j, 1, 4){
cin>>a[i][j];
if(a[i][j] == 'O') //记录空点位置
if(!start.x[0]) start.x[0] = i, start.y[0] = j;
else start.x[1] = i, start.y[1] = j;
}
start.s = getHash();
start.time = 0;
begin = start;
start.who = 0;
begin.who = 1;
q.push(start);
q.push(begin);
v[getHash(begin)] = v[getHash(start)] = 1;
while(!q.empty()){ //bfs
Node now = q.front();
q.pop();
rep(i, 0, 1){
rep(j, 1, 4){
X = now.x[i] + l[j]; Y = now.y[i] + r[j];
if(X <= 0 || X > 4 || Y <= 0 || Y > 4 || X == now.x[i^1] && Y == now.y[i^1]) continue; //不能出界,也不能走到另外一个空点
id = ((X - 1) << 2) + Y - 1;
kong = ((now.x[i] - 1) << 2) + now.y[i] - 1;
if(((now.s >> id) & 1) == now.who){ //如果是到这个棋走
tmp = now;
tmp.s &= ~(1 << id); //交换
tmp.s |= tmp.who << kong; //位置
tmp.x[i] = X;
tmp.y[i] = Y;
if(v[getHash(tmp)]) continue;
v[getHash(tmp)] = 1;
tmp.time++;
tmp.who^=1;
if(Win(tmp)){
printf("%d\n", tmp.time);
return 0;
}
q.push(tmp);
}
}
}
}
return 0;
}

【洛谷 P2346】四子连棋(状态压缩,搜索)的更多相关文章

  1. 洛谷P2346四子连棋

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

  2. P2346 四子连棋

    P2346 四子连棋 迭代加深++ 题意描述 在一个4*4的棋盘上摆放了14颗棋子,其中有7颗白色棋子,7颗黑色棋子,有两个空白地带,任何一颗黑白棋子都可以向上下左右四个方向移动到相邻的空格,这叫行棋 ...

  3. Codevs 四子连棋 (迭代加深搜索)

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

  4. 洛谷 P2704 [NOI2001]炮兵阵地 (状态压缩DP+优化)

    题目描述 司令部的将军们打算在NM的网格地图上部署他们的炮兵部队.一个NM的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P" ...

  5. 洛谷 P1896 [SCOI2005]互不侵犯 (状态压缩DP)

    题目描述 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. 注:数据有加强(2018/4/25) ...

  6. 洛谷 P2622 关灯问题II (状态压缩+BFS)

    题目描述 现有n盏灯,以及m个按钮.每个按钮可以同时控制这n盏灯--按下了第i个按钮,对于所有的灯都有一个效果.按下i按钮对于第j盏灯,是下面3中效果之一:如果a[i][j]为1,那么当这盏灯开了的时 ...

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

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

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

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

  9. Codevs p1004 四子连棋

                          四子连棋 题目描述 Description 在一个4*4的棋盘上摆放了14颗棋子,其中有7颗白色棋子,7颗黑色棋子,有两个空白地带,任何一颗黑白棋子都可以向 ...

随机推荐

  1. crm踩坑记(一)

    目录 antd es6 Object.entries() Object.keys() Object.getOwnPropertyNames() 很神奇的用法!!! eslint 傻逼 其他 参考 an ...

  2. I/O Handler的管理(3)

    另外连接地址:http://blogs.readthedocs.org/zh_CN/latest/Handler_mgr.html 本章目录 I/O Handler的管理 IO句柄与Select_Re ...

  3. 「日常训练」「小专题·图论」 Cow Contest (1-3)

    题意 分析 问题是要看出来这是个floyd闭包问题.我没看出来- - 分析之后补充. 代码 // Origin: // Theme: Graph Theory (Basic) // Date: 080 ...

  4. 不同浏览器css引入外部字体的方式

    /** * 字体后缀和浏览器有关,如下所示 * .TTF或.OTF,适用于Firefox 3.5.Safari.Opera * .EOT,适用于Internet Explorer 4.0+ * .SV ...

  5. url解读

    我刚刚学习的时候,我抓到包不知道哪个是协议.哪个是是服务器地址.哪个是端口号...不知道有没有老铁遇到跟我一样的. 接口:http://172.168.12.0:8888/old/login.do 解 ...

  6. 重写selenium 的 click()操作,使其变成隐式等待

    selenium 页面常会因为页面加载慢而出现element 不能被点击到的情况,比如加载过程中出现遮罩,导致element 可见不可点.以下方法重写click(),用隐式等待解决这个问题. 基本思路 ...

  7. 用jsp实现省市区三级联动下拉

    jsp+jquery实现省市区三级联动下拉 不少系统都需要实现省市区三级联动下拉,像人口信息管理.电子商务网站.会员管理等,都需要填写地址相关信息.而用ajax实现的无刷新省市区三级联动下拉则可以改善 ...

  8. linux学习笔记---学习总结②

    table ----> 展示数据 table --->表格 border cellspacing cellpadding width height tr --->行 align th ...

  9. 剑指offer-旋转数组的最小数字06

    题目描述 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素. 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋 ...

  10. Annoy解析

    Annoy是高维空间求近似最近邻的一个开源库. Annoy构建一棵二叉树,查询时间为O(logn). Annoy通过随机挑选两个点,并使用垂直于这个点的等距离超平面将集合划分为两部分. 如图所示,图中 ...