hdu 1401 Solitaire 双向广度搜索

 
 
 
 
在一个 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[N][N][N][N][N][N][N][N]; //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][n][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;
}
原文地址:https://www.cnblogs.com/zxj015/p/2740256.html