zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    $(document).ready(function(){}) 与 window.onload = function(){} 区别
    [如何在Mac下使用gulp] 1.创建项目及安装gulp
    Mac 执行 gulp 报错 bash: gulp: command not found
    css 字体单位之间的区分以及字体响应式实现
    [nodejs]在mac环境下如何将node更新至最新?
    [angular 1.x] 使用select 实现下拉列表 ngoptions 与 ngrepeat的取舍
    事件冒泡、事件捕获、事件委托初探
    Android 随机铃声管理器
    git 强制恢复到某一版本
    混乱中生存
  • 原文地址:https://www.cnblogs.com/zxj015/p/2740256.html
Copyright © 2011-2022 走看看