题目链接

算法:BFS

//2014-02-05更新

*******************************2013-10-15*******************************

PS:被卡过2天。日期:2013-10-14 ~ 2013-10-15 17:28:21

此题卡了我一天,原因是宽搜时方向搞错= =(汗= =),而这个错误我竟然检查了好久= =!!

(大神不要笑,我用来超多的代码来实现= =是别人提交代码的5倍以上,,,200多行= =)

2014.01.02 PS: 我承认我是脑残了,现在已会写bfs,改天有时间修改下,下面这个程序很好的证明了我不会搜索= =

#include <iostream>
#include <cstring>
#include <queue> using namespace std;
enum pa{NUL, LEFT, UP, RIGHT, DOWN}; //四个方向
enum color{O, W, B}; //白色用W表示,黑色用B表示,NUL就表示空格
struct st
{
color m[4][4];
short d; //次数
short x1, y1, x2, y2; //空格的位置
bool who; //0表示到白棋走,1表示黑棋走
pa p1, p2; //空格之前所在的位置,即以本格子来看从哪个位置是移动之前的状态
st& operator= (const st& s)
{
memcpy(m, s.m, sizeof(m));
d=s.d; who=s.who;
p1=s.p1; p2=s.p2;
x1=s.x1; x2=s.x2;
y1=s.y1; y2=s.y2;
return *this;
}
st(){memset(m, 0, sizeof(m)); d=0; x1=x2=y1=y2=-1; p1=p2=NUL; who=1;}
}state;
queue<st> q;
int i, j; void readin()
{
char chartemp;
for(i = 0; i < 4; i++) for(j = 0; j < 4; j++)
{
cin >> chartemp;
if(chartemp == 'W') state.m[i][j] = W;
else if(chartemp == 'B') state.m[i][j] = B;
else
{
state.m[i][j] = O;
if(state.x1 == -1)
state.x1 = i, state.y1 = j;
else
state.x2 = i, state.y2 = j;
}
}
} void chu()
{
st t = state;
if(t.x1+1<4 && t.m[t.x1+1][t.y1] != O) //第一个空格 向下移
{
t.p1 = UP; t.p2 = NUL;
t.x1++; t.m[t.x1-1][t.y1] = t.m[t.x1][t.y1];
t.m[t.x1][t.y1] = O; t.d++;
t.who = t.m[t.x1-1][t.y1]-1; t.who = !t.who;
q.push(t);
}
t = state;
if(t.x2+1<4 && t.m[t.x2+1][t.y2] != O) //第二个空格 向下移
{
t.p2 = UP; t.p1 = NUL;
t.x2++; t.m[t.x2-1][t.y2] = t.m[t.x2][t.y2];
t.m[t.x2][t.y2] = O; t.d++;
t.who = t.m[t.x2-1][t.y2]-1; t.who = !t.who;
q.push(t);
}
t = state;
if(t.y1+1<4 && t.m[t.x1][t.y1+1] != O) //第一个空格 向右移
{
t.p1 = LEFT; t.p2 = NUL;
t.y1++; t.m[t.x1][t.y1-1] = t.m[t.x1][t.y1];
t.m[t.x1][t.y1] = O; t.d++;
t.who = t.m[t.x1][t.y1-1]-1; t.who = !t.who;
q.push(t);
}
t = state;
if(t.y2+1<4 && t.m[t.x2][t.y2+1] != O) //第二个空格 向右移
{
t.p2 = LEFT; t.p1 = NUL;
t.y2++; t.m[t.x2][t.y2-1] = t.m[t.x2][t.y2];
t.m[t.x2][t.y2] = O; t.d++;
t.who = t.m[t.x2][t.y2-1]-1; t.who = !t.who;
q.push(t);
}
t = state;
if(t.x1 > 0 && t.m[t.x1-1][t.y1] != O) //第一个空格 向上移
{
t.p1 = DOWN; t.p2 = NUL;
t.x1--; t.m[t.x1+1][t.y1] = t.m[t.x1][t.y1];
t.m[t.x1][t.y1] = O; t.d++;
t.who = t.m[t.x1+1][t.y1]-1; t.who = !t.who;
q.push(t);
}
t = state;
if(t.x2 > 0 && t.m[t.x2-1][t.y2] != O) //第二个空格 向上移
{
t.p2 = DOWN; t.p1 = NUL;
t.x2--; t.m[t.x2+1][t.y2] = t.m[t.x2][t.y2];
t.m[t.x2][t.y2] = O; t.d++;
t.who = t.m[t.x2+1][t.y2]-1; t.who = !t.who;
q.push(t);
}
t = state;
if(t.y1 > 0 && t.m[t.x1][t.y1-1] != O) //第一个空格 向左移
{
t.p1 = RIGHT; t.p2 = NUL;
t.y1--; t.m[t.x1][t.y1+1] = t.m[t.x1][t.y1];
t.m[t.x1][t.y1] = O; t.d++;
t.who = t.m[t.x1][t.y1+1]-1; t.who = !t.who;
q.push(t);
}
t = state;
if(t.y2 > 0 && t.m[t.x2][t.y2-1] != O) //第二个空格 向左移
{
t.p2 = RIGHT; t.p1 = NUL;
t.y2--; t.m[t.x2][t.y2+1] = t.m[t.x2][t.y2];
t.m[t.x2][t.y2] = O; t.d++;
t.who = t.m[t.x2][t.y2+1]-1; t.who = !t.who;
q.push(t);
}
} bool check(const st& s)
{
int x, y; pa p; bool bp = 1;
if(s.p1 != NUL) p = s.p1; else {p = s.p2; bp = 0;}
switch(p)
{
case UP:
x = (bp?s.x1-1:s.x2-1); y = (bp?s.y1:s.y2);
break;
case DOWN:
x = (bp?s.x1+1:s.x2+1); y = (bp?s.y1:s.y2);
break;
case RIGHT:
x = (bp?s.x1:s.x2); y = (bp?s.y1+1:s.y2+1);
break;
case LEFT:
x = (bp?s.x1:s.x2); y = (bp?s.y1-1:s.y2-1);
break;
default:
return 0;
}
if((s.m[x][0]==s.m[x][1]&&s.m[x][1]==s.m[x][2]&&s.m[x][2]==s.m[x][3]) ||
(s.m[0][y]==s.m[1][y]&&s.m[1][y]==s.m[2][y]&&s.m[2][y]==s.m[3][y]) ||
(s.m[0][0]==s.m[1][1]&&s.m[1][1]==s.m[2][2]&&s.m[2][2]==s.m[3][3]) ||
(s.m[0][3]==s.m[1][2]&&s.m[1][2]==s.m[2][1]&&s.m[2][1]==s.m[3][0]) )
return 1;
return 0;
} int main()
{
readin();
chu();
st s, t;
int n = 0; //迭代
while(++n != 10000000)
{
s = q.front(); q.pop();
if(check(s)) break;
t = s;
// 要判断是否这个点是从原来方向移动得到的,如果要向上移,则p域就不能是下面,否则会大大损耗空间和时间
if(t.x1+1<4 && t.p1 != DOWN && t.m[t.x1+1][t.y1] != O && t.m[t.x1+1][t.y1]-1 == t.who) //第一个空格 向下移
{
t.p1 = UP; t.p2 = NUL;
t.x1++; t.m[t.x1-1][t.y1] = t.m[t.x1][t.y1];
t.m[t.x1][t.y1] = O; t.d++; t.who = !t.who;
q.push(t);
}
t = s;
if(t.x2+1<4 && t.p2 != DOWN && t.m[t.x2+1][t.y2] != O && t.m[t.x2+1][t.y2]-1 == t.who) //第二个空格 向下移
{
t.p2 = UP; t.p1 = NUL;
t.x2++; t.m[t.x2-1][t.y2] = t.m[t.x2][t.y2];
t.m[t.x2][t.y2] = O; t.d++; t.who = !t.who;
q.push(t);
}
t = s;
if(t.y1+1<4 && t.p1 != RIGHT && t.m[t.x1][t.y1+1] != O && t.m[t.x1][t.y1+1]-1 == t.who) //第一个空格 向右移
{
t.p1 = LEFT; t.p2 = NUL;
t.y1++; t.m[t.x1][t.y1-1] = t.m[t.x1][t.y1];
t.m[t.x1][t.y1] = O; t.d++; t.who = !t.who;
q.push(t);
}
t = s;
if(t.y2+1<4 && t.p2 != RIGHT && t.m[t.x2][t.y2+1] != O && t.m[t.x2][t.y2+1]-1 == t.who) //第二个空格 向右移
{
t.p2 = LEFT; t.p1 = NUL;
t.y2++; t.m[t.x2][t.y2-1] = t.m[t.x2][t.y2];
t.m[t.x2][t.y2] = O; t.d++; t.who = !t.who;
q.push(t);
}
t = s;
if(t.x1 > 0 && t.p1 != UP && t.m[t.x1-1][t.y1] != O && t.m[t.x1-1][t.y1]-1 == t.who) //第一个空格 向上移
{
t.p1 = DOWN; t.p2 = NUL;
t.x1--; t.m[t.x1+1][t.y1] = t.m[t.x1][t.y1];
t.m[t.x1][t.y1] = O; t.d++; t.who = !t.who;
q.push(t);
}
t = s;
if(t.x2 > 0 && t.p2 != UP && t.m[t.x2-1][t.y2] != O && t.m[t.x2-1][t.y2]-1 == t.who) //第二个空格 向上移
{
t.p2 = DOWN; t.p1 = NUL;
t.x2--; t.m[t.x2+1][t.y2] = t.m[t.x2][t.y2];
t.m[t.x2][t.y2] = O; t.d++; t.who = !t.who;
q.push(t);
}
t = s;
if(t.y1 > 0 && t.p1 != LEFT && t.m[t.x1][t.y1-1] != O && t.m[t.x1][t.y1-1]-1 == t.who) //第一个空格 向左移
{
t.p1 = RIGHT; t.p2 = NUL;
t.y1--; t.m[t.x1][t.y1+1] = t.m[t.x1][t.y1];
t.m[t.x1][t.y1] = O; t.d++; t.who = !t.who;
q.push(t);
}
t = s;
if(t.y2 > 0 && t.p2 != LEFT && t.m[t.x2][t.y2-1] != O && t.m[t.x2][t.y2-1]-1 == t.who) //第二个空格 向左移
{
t.p2 = RIGHT; t.p1 = NUL;
t.y2--; t.m[t.x2][t.y2+1] = t.m[t.x2][t.y2];
t.m[t.x2][t.y2] = O; t.d++; t.who = !t.who;
q.push(t);
}
} cout << s.d << endl;
return 0;
}

*******************************2014-02-05*******************************

算法:BFS+Hash判重

裸BFS后,看了题解,有 Hash判重 知识,可算长姿势了。

Hash判重:将图看成一串数字,我们可以发现,这可以当作n进制的数看待,那么hash就有着落了。。我们将这个n进制数转换为十禁止,再开个数组,就可以hash了

这题的图元素只有3个,那么我们就可以将它看成3进制数来做hash。

注意:做hash的时候的mod要用质数(自己想为什么),因为这个图的长度为16,有7个2,那么经过粗略计算,这个hash的mod在40700000的后面,自己写了个小prime判定,找出了一个质数 40700017,就用它了。

代码:

#include <iostream>
#include <cstring>
using namespace std; struct Map {
int m[4][4], x1, x2, y1, y2;
int ans, who;
Map& operator= (Map& a) { memcpy(m, a.m, sizeof(a.m)); x1=a.x1; x2=a.x2; y1=a.y1; y2=a.y2; ans=a.ans; who=a.who; return *this; }
}q[600009]; //我们模拟队列,开那么多应该够了吧。。不够就用循环队列
Map t; //作为全局temp const int mod = 40700017;
bool Hash[mod]; bool check(int f) {
//判断行和列
for(int i = 0; i < 4; ++i)
if( (q[f].m[i][0]==q[f].m[i][1] && q[f].m[i][1]==q[f].m[i][2] && q[f].m[i][2]==q[f].m[i][3]) ||
(q[f].m[0][i]==q[f].m[1][i] && q[f].m[1][i]==q[f].m[2][i] && q[f].m[2][i]==q[f].m[3][i]) )
return true;
//判断斜边
if( (q[f].m[0][0]==q[f].m[1][1] && q[f].m[1][1]==q[f].m[2][2] && q[f].m[2][2]==q[f].m[3][3]) ||
(q[f].m[0][3]==q[f].m[1][2] && q[f].m[1][2]==q[f].m[2][1] && q[f].m[2][1]==q[f].m[3][0]) )
return true;
return false;
} void swap(int x, int y, int xx, int yy, int w) {
t.m[x][y] = t.m[xx][yy];
t.m[xx][yy] = 0;
if(w == 1) t.x1 = xx, t.y1 = yy;
else t.x2 = xx, t.y2 = yy;
t.who = t.m[x][y];
} bool hash(Map& s) {
//k是3^x次方的结果
int i, j, k = 1, h = 0;
for(i = 0; i < 4; ++i)
for(j = 0; j < 4; ++j) {
h += s.m[i][j] * k;
k *= 3;
}
h %= mod;
if(Hash[h]) return false;
Hash[h] = 1;
return true;
} void bfs() {
int f = 0, l = 1;
int x1, y1, x2, y2;
while(f != l) {
if(check(f)) { cout << q[f].ans; break; }
q[f].ans++;
x1 = q[f].x1; y1 = q[f].y1; x2 = q[f].x2; y2 = q[f].y2;
//8种情况。。我承认可以简略代码的,但是算了。这样看起来壮观 >_<
if(x1 > 0 && q[f].m[x1-1][y1] != q[f].who) { t = q[f]; swap(x1, y1, x1-1, y1, 1); if(hash(t)) q[l++] = t; }
if(x1 < 3 && q[f].m[x1+1][y1] != q[f].who) { t = q[f]; swap(x1, y1, x1+1, y1, 1); if(hash(t)) q[l++] = t; }
if(y1 > 0 && q[f].m[x1][y1-1] != q[f].who) { t = q[f]; swap(x1, y1, x1, y1-1, 1); if(hash(t)) q[l++] = t; }
if(y1 < 3 && q[f].m[x1][y1+1] != q[f].who) { t = q[f]; swap(x1, y1, x1, y1+1, 1); if(hash(t)) q[l++] = t; }
if(x2 > 0 && q[f].m[x2-1][y2] != q[f].who) { t = q[f]; swap(x2, y2, x2-1, y2, 2); if(hash(t)) q[l++] = t; }
if(x2 < 3 && q[f].m[x2+1][y2] != q[f].who) { t = q[f]; swap(x2, y2, x2+1, y2, 2); if(hash(t)) q[l++] = t; }
if(y2 > 0 && q[f].m[x2][y2-1] != q[f].who) { t = q[f]; swap(x2, y2, x2, y2-1, 2); if(hash(t)) q[l++] = t; }
if(y2 < 3 && q[f].m[x2][y2+1] != q[f].who) { t = q[f]; swap(x2, y2, x2, y2+1, 2); if(hash(t)) q[l++] = t; }
f++;
}
} int main() {
char t; bool ok = 1;
for(int i = 0; i < 4; ++i) for(int j = 0; j < 4; ++j) {
cin >> t;
switch(t) {
case 'B': q[0].m[i][j] = 2; break;
case 'W': q[0].m[i][j] = 1; break;
case 'O': q[0].m[i][j] = 0;
if(ok) q[0].x1 = i, q[0].y1 = j, ok = 0;
else q[0].x2 = i, q[0].y2 = j;
break;
}
}
bfs();
return 0;
}

  

【wikioi】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. BFS搜索算法应用_Codevs 1004 四子连棋

    #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <algorithm> #include <cs ...

  4. CODEVS——T 1004 四子连棋

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

  5. CODEVS 1004四子连棋

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

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

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

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

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

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

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

  9. codevs1004四子连棋

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

随机推荐

  1. The Perfect Stall (incomplete)

    恩,一看就知道是一道二分图最大匹配的题. 感动得发现自己不会做..果然我是太弱了.学校里真是麻烦死,根本没有时间好吗. (NOIP)会不会感动地滚粗啊? 然后稍微看看,恩,匈牙利算法. 真是感动得落泪 ...

  2. Linux下crontab命令的用法

    cron来源于希腊单词chronos(意为“时间”),是linux系统下一个自动执行指定任务的程序.例如,你想在每晚睡觉期间创建某些文件或文件夹的备份,就可以用cron来自动执行. 服务的启动和停止 ...

  3. 关于Linux下进程间使用共享内存和信号量通信的时的编译问题

    今天在编译一个使用信号量实现进程同步时,出现了库函数不存在的问题.如下图 编译结果实际上是说,没include相应的头文件,或是头文件不存在(即系统不支持该库函数) 但我man shm_open是可以 ...

  4. Windows系统时间同步出错解决办法

    有时候我们设置本地时间与Internet时间同步时,经常连接服务器time.windows.com超时,导致时间同步失败,解决办法如下: 利用快捷键"Win+R"调出运行框,输入: ...

  5. 利用FFmpeg生成视频缩略图 2.1.8

    1.下载FFmpeg文件包,解压包里的\bin\下的文件解压到 D:\ffmpeg\ 目录下. 下载地址 http://ffmpeg.zeranoe.com/builds/win32/static/ ...

  6. [Android Pro] AndroidStudio导出jar包

    reference :  http://blog.csdn.net/beijingshi1/article/details/38681281 不像在Eclipse,可以直接导出jar包.Android ...

  7. linux shell的切换

    查看系统可用shell种类:(一般是bash shell) ➜ ~ chsh -l /bin/sh /bin/bash /sbin/nologin /bin/dash /bin/zsh 修改当前的sh ...

  8. errno 错误码

    转自:http://baike.baidu.com/link?url=uX-q7K-TTL-5AFNT-hjhAP6fvgAwvsNkIMqJqJ3GEspYgtQXsovEEzpqmQ3ZmAgql ...

  9. SQL 查询CET使用领悟

    用到sql的遍历循环查询,如果不考虑用CET,估计又到了自己造轮子的时代了,现在觉得sql的CET确实是个好东西,针对SQL的递归查询,很是不错的方法: with etcRecommandINfo2( ...

  10. List Copy

    //要复制的实例必须可序列化,包括实例引用的其它实例都必须在类定义时加[Serializable]特性. public static T Copy<T>(T RealObject) { u ...