您的位置:首页 > 大数据 > 人工智能

hdu 1401 Solitaire 双向广度搜索

2011-03-26 19:48 369 查看
http://acm.hdu.edu.cn/showproblem.php?pid=1401

转自:http://www.cppblog.com/IronOxide/archive/2010/08/19/123928.html
在一个 8 * 8 的棋盘上,有四个棋子,每颗棋子可在上,下,左,右,四个方向进行四种操作,四种操作是一
下的某一种:
1. 若相邻格有棋子,则可像跳棋一样,跳过去,到达对称的一格。
2.若相邻格为空,则可直接移过去。

问能否从一种状态在8步之内变成另一种状态?

题目分析:

明显的一道搜索题,但是应该选取怎样的策略去搜索呢?
估计一下普通广度优先搜索的复杂度:有4颗棋子,每个棋子最多有4种变换方式,所以一个棋盘可以对应16种状态,走8步的话,就有16^8 = 2^32的计算量,这几乎不能完成任务。

考虑一下,这个题目的特别之处:给定两种状态,判断是否可达。操作的特别之处:操作具有可逆性,也就是说,从A到B状态,B到A依然是可行的。

所以,可虑一下双向广搜,先判断复杂度:两个状态各进行4步操作,计算量为16^4=2^16,时空复杂度都可以满足。考虑到这里不要求最小步数,我们可以先把两种状态各走四步的可达状态先用广搜算出存表,然后直接查表比较即可。
#include <iostream>
#include <stdio.h>
#include <queue>
#include <algorithm>
using namespace std;

const int N=8;
struct node{
int i, j;
};
struct Mode{
node a[4];
};
char hash

; //hash表,2个一组作为一个piece的坐标,4个pieces一组,作为一个状态储存。
int dir[4][2] = {{1,0},{0,1},{-1,0},{0,-1}}; //依旧 4个方向搜。。
bool reachable; //判断可以到达。。
Mode s; //这个Mode很有用,用来接input,还能用来s=front(),也能在判断有无piece的Vacant函数中用。。

bool cmp(const node &a, const node &b) //用在sort()中,是<algorithm>文件中的一个算法。
{
if (a.i != b.i)
return a.i < b.i;
return a.j < b.j;
}
//hash表,就是visited or not..还可以通过计数来判断走了多少步,用法很广,尽情发挥
void sethash()
{
int i, j , k, l, m, n, o, p;
for (i=0; i<8; i++)
for (j=0; j<8; j++)
for (k=0; k<8; k++)
for (l=0; l<8; l++)
for (m=0; m<8; m++)
for (n=0; n<8; n++)
for (o=0; o<8; o++)
for (p=0; p<8; p++)
hash[i][j][k][l][m]
[o][p] = 10;
}
//判断node-t这一步是否可以走
bool vacant(node &t) //judge whether this location is available or not
{
int i;
for (i=0; i<4; i++)
if (s.a[i].i == t.i && s.a[i].j == t.j)
return false;
return true;
}
//给Mode-t赋值fuck。。
void set(Mode t, char fuck)
{
hash[t.a[0].i][t.a[0].j][t.a[1].i][t.a[1].j][t.a[2].i][t.a[2].j][t.a[3].i][t.a[3].j] = fuck;
}
char get(Mode t)
{
return hash[t.a[0].i][t.a[0].j][t.a[1].i][t.a[1].j][t.a[2].i][t.a[2].j][t.a[3].i][t.a[3].j];
}
//This function is written for changing (i, j) to (i-1, j-1), for I wanna curtail space.
void change()
{
int i;
for (i=0; i<4; i++)
{
s.a[i].i--;
s.a[i].j--;
}
}

void DBFS(queue<Mode>& q, bool fuck)
{
s = q.front();
q.pop();
int i, j;
Mode t; //temp
for (i=0; i<4; i++)
{//第i个piece
for (j=0; j<4; j++)
{//第j个direction
t = s;
t.a[i].i += dir[j][0];
t.a[i].j += dir[j][1];
//check whether space t.a[i] is available or not
if (!vacant(t.a[i]))//若目标有棋,跳过该棋。
{
t.a[i].i += dir[j][0];
t.a[i].j += dir[j][1];
}
if (t.a[i].i<0 || t.a[i].i>7 || t.a[i].j<0 || t.a[i].j>7) //if(true) then, this piece is outside map
continue;
sort(t.a, t.a+4, cmp); //Why sort just for the fact that {4,4}{4,5}{4,6}{4,7} and {4,4}{4,6}{4,5}{4,7} is the same situation.
char it = get(t);
if (fuck) //if fuck=true, then q = q1
{

if (it < 10) // it indicates the queue(q1/q2) and steps,
{
reachable = true; //for it < 10, that indicates that the mode has been found from q2
return;
}
else if (it == 10)
{//never reach this mode ,so.....
char m = get(s)+1; //-1 or +1 is decided on the following reason, steps from q1 will be larger and larger, steps from q2 will be more and more small..
set(t, m);
if (m < 15)
q.push(t);
}
}
else
{
if (it > 10)
{ reachable = true;
return;
}
else if (it == 10)
{
char m = get(s)-1;
set(t, m);
if (m>5)
q.push(t);
}
}
}
}
}

int main()
{
while (scanf("%d %d", &s.a[0].i, &s.a[0].j) != EOF)
{
int i;
queue<Mode> q1, q2; //define q1 and q2 here can save the time of setting zero.
sethash();

for (i=1; i<4; i++)
scanf("%d %d", &s.a[i].i, &s.a[i].j);
change(); //change (i,j) to (i-1, j-1), for saving space.
sort(s.a, s.a+4, cmp); // why from 0 to 4, I can't understand..
set(s, 11);
q1.push(s);

for (i=0; i<4; i++)
scanf("%d %d", &s.a[i].i, &s.a[i].j);
change();
sort(s.a, s.a+4, cmp);
set(s, 9);
q2.push(s);

reachable = false;
while (!q1.empty() || !q2.empty())
{
if (!q1.empty())
{
DBFS(q1, true);
}
if (reachable)
break;
if (!q2.empty())
{
DBFS(q2, false);
}
if (reachable)
break;
}
if (reachable)
printf("YES\n");
else
printf("NO\n");
}
// system("pause");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: