【POJ1198 Solitaire 】 思路+解題報告+測試數據生成器

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
//#define DBG
//#define INPUT
//#define DBG1
using namespace std;

/**
        Problem: poj1198 - Solitaire
        Begin Time : 18:33 15th/Mar/2012
        End Time:   2:40 a.m. 16th/Mar/2012
        Test Data:
        見數據生成器代碼
        Standard Output:
        用本程序對拼即可
        Thought:
          這個代碼寫的太垃圾了,比較崩潰。
          ①:狀態壓縮:
            棋盤上只有四個棋子,一行數字(x1 y1 x2 y2 x3 y3 x4 y4)
            代表了四個棋子在棋盤上的位置。
            我們把各個棋子按照x的大小進行排序。
            然後把其變成一個八位數來表示當前的棋盤狀態
          ②:HASH排重 (*)
            把待搜索的棋盤狀態插入自己的hash表中。
            注意,由於DFS是雙向的,hash表要維護兩個,一個是正向搜索的hash表
            一個是反向搜索的hash表。如果其的key發生衝突並且內容相同,那麼插入失敗。
          ③:狀態搜索:
            每次從兩個隊列(一個表示從開始狀態,一個表示從結束狀態)搜索中取出表示該次搜索
            應該搜索的狀態,然後將搜索的內容在不同的hash表裏進行檢索,例如:
            從begin_queue[front]取出的bval1(表示從開始狀態搜索到的某個中間狀態)
            應該在end_hash中檢索,如果在end_hash中找到了該狀態,並且該狀態對應的
            end_deep(從結束狀態到這個中間狀態經過的步數)與當前狀態的deep加起來小於等於8
            那麼就代表找到了,標誌isFound = true;然後輸出
          ④:如何搜索
            搜索的時候還是四個向量,左右上下,只不過進行左右上下搜索的時候記得判斷一下週圍是否有棋子
            這個做法是把壓縮過的狀態還原成int tmp[8],然後找移動後的棋子tmp[i],tmp[i+1]在其他的tmp中有
            沒有相同的,2*i是x,2*i+1是y
            如果tmp[2*i] == tmp[2*j] && tmp[2*i + 1] == tmp[2*j + 1]的話,就代表i移動後與j重疊。
            按照“跳過子”的規則進行移動。

        Knowledge:
          HASH排重+狀態壓縮+雙向BFS搜索
        The Experience:
            WA點1 : 在進行棋子的移動的時候,switch(dir) case 0 1 2 3寫成了 1 2 3 4,不應該犯!
            WA點2:非常腦殘的在hash表中每個狀態沒有保存對應的深度!所以有時候從beginState搜索到beginDeep = 3
                    的時候,在endHash表中找到了一個endDeep = 6 的狀態與之對應,由於沒有保存endHash中每個狀態的深度
                    所以這時候輸出了,WA了4次(貌似)
*/
const int HASHKEY = 100003;
const int HASHEND = 2;
const int HASHBEGIN = 1;
const int dx[] = {-1,1,0,0};
const int dy[] = {0,0,-1,1};
int bs[8];  ///開始狀態
int es[8];  ///結束狀態
int bhash[200000];
int bnext[200000];
int ehash[200000];
int enext[200000];
int _bdeep1[500000];
int _edeep1[500000];
int _bdeep[500000];
int _edeep[500000];
int bque[500000];
int eque[500000];
bool isFound;
int bnow,enow;
int bfront,brear;
int bdeep,edeep;
int efront,erear;
bool checkHash(int val,int sel,int dp)
{
    int tmp = val % HASHKEY;
    if( sel == HASHBEGIN )
    {
        while(bnext[tmp])
        {
            if ( bhash[ bnext[tmp] ] == val )
            {
#ifdef DBG
                printf("The %d of bhash is %d\n",bnext[tmp],val);
#endif
                if ( _bdeep1[ bnext[tmp] ] + dp <= 8)
                    return true;
                else
                    return false;
            }
            tmp = bnext[tmp];
        }
    }
    if( sel == HASHEND )
    {
        while(enext[tmp])
        {
            if (ehash[ enext[tmp] ] == val)
            {
#ifdef DBG
                printf("The %d of ehash is %d\n",bnext[tmp],val);
#endif
                if (_edeep1 [ enext[tmp] ] + dp <= 8 )
                    return true;
                else
                    return false;
            }
            tmp = enext[tmp];
        }
    }
    return false;
}
bool insert_end(int es,int dp)
{
    int key = es % HASHKEY;
    while( enext[key] )
    {
        if( ehash[ enext[key] ] == es) return false;
        key = enext[key];
    }
    enext[key] = enow;
    _edeep1[enow] = dp;
    ehash[enow] = es;
    enow++;
    return true;
}
bool insert_begin(int bs,int dp)
{
    ///檢查是否在hashend裏
    int key = bs % HASHKEY;
    while( bnext[key] )
    {
        if ( bhash[ bnext[key] ] == bs ) return false;
        key = bnext[key];
    }
    bnext[key] = bnow;
    bhash[bnow] = bs;
    _bdeep1[bnow] = dp;
    bnow++;
    return true;
}
void exchange(int* a, int* b)
{
    int tmp;
    tmp = *a;
    *a = *b;
    *b = tmp;
}
int getNum(int a[8])
{
    for(int i = 0 ; i < 8 ; i = i + 2)
    {
        for (int j = i + 2 ; j < 8 ; j = j + 2)
        {
            if ( a[i] > a[j] )
            {
                exchange(&a[i],&a[j]);
                exchange(&a[i+1],&a[j+1]);
            }
            if ( a[i] == a[j] )
            {
                if ( a[i+1] > a[j+1] )
                {
                    exchange(&a[i+1],&a[j+1]);
                }
            }
        }
    }
    ///排序
    int res = 0 ;
    for(int i = 0 ; i < 8 ; i++)
    {
        res = res * 10 + a[i];
    }
    return res;
}
/**
int getNum(const int a[8])
{
    ///這裏寫的有問題
    ///應該把node按照x,y的順序排序之後再給值!
    int res = 0;
    for(int i = 0 ; i < 8; i++)
    {
        res = res * 10 + a[i];
    }
    return res;
}*/
bool checkMove(int* destState,int oriState[8],int ind,int dir)
{
    for(int i = 0 ; i < 8; i = i + 2)
    {
        if( destState[ind] == oriState[i]  )
        {
            if (destState[ind+1] == oriState[i+1]  )
            {
                ///棋子發生重疊
                ///dir - >方向
                switch(dir)
                {
                case 0:  ///上,x-1,x - 1 -1 ->越過棋子
                    if( destState[ind] - 1 > 0 )  ///不出界
                    {
                        destState[ind] = destState[ind] - 1;
                        return true;
                    }
                    break;
                case 1:  ///下, x+1
                    if ( destState[ind] + 1 < 9 )
                    {
                        destState[ind] += 1;
                        return true;
                    }
                    break;
                case 2:  ///左,y-1
                    if ( destState[ind+1] - 1 > 0 )
                    {
                        destState[ind+1] -=1;
                        return true;
                    }
                    break;
                case 3:  ///右,y+1
                    if ( destState[ind+1] + 1 < 9 )
                    {
                        destState[ind+1] +=1;
                        return true;
                    }
                    break;
                }
                return false;
            }
        }
    }
    /////////////////////上方爲檢測棋子重疊
    if ( destState[ind] < 1 || destState[ind] > 8
            || destState[ind+1] > 8 || destState[ind+1] < 1 )
        return false;
    return true;
}
void segNum(int* a,int val)
{
    for(int i = 7 ; i >= 0  ; i--)
    {
        a[i] = val % 10;
        val = val / 10;
    }
}
void Solve()
{
    int btmp[8];
    int etmp[8];
    int btmp1[8],etmp1[8];
    int bval = 0;
    int bval1 = 0;
    int eval = 0;
    int bdeep1,edeep1;
    int eval1 = 0;
    int bnum,_enum; //enum is the keyword
    isFound = false;
    bfront = 1;
    brear = 2;
    bdeep = edeep = 0;
    efront = 1;
    erear = 2;
    bnow = enow = 1;
    memcpy(btmp,bs,sizeof(int)*8);
    memcpy(etmp,es,sizeof(int)*8);
    memset(bque,0,sizeof(bque));
    memset(eque,0,sizeof(eque));
    memset(bnext,0,sizeof(bnext));
    memset(enext,0,sizeof(enext));
    memset(bhash,0,sizeof(bhash));
    memset(ehash,0,sizeof(ehash));
    bnum = getNum(btmp);
    _enum = getNum(etmp);
    insert_begin(bnum,bdeep);
    insert_end(_enum,edeep);
    bque[bfront] = bnum;
    eque[efront] = _enum;
    _bdeep[bfront] = bdeep;
    _edeep[efront] = edeep;
    while( bfront < brear && efront < erear && !isFound )
    {
        ///雙向搜索
        bval = bque[bfront];
        eval = eque[efront];
        bdeep = _bdeep[bfront];
        edeep = _edeep[efront];
//        if ( bdeep + edeep >= 6 )
        if(checkHash(bval,HASHEND,bdeep))
        {
            isFound = true;
        }
        if(checkHash(eval,HASHBEGIN,edeep))
        {
            isFound = true;
        }
#ifdef DBG
        if( isFound )
        {
            printf("Founded at deep of : \n");
            printf("Begin Deep : %d \n",bdeep);
            printf("End Deep : %d \n",edeep);
            printf("The end is %d\n",eval1);
            printf("The Start is %d\n",bval1);
        }
#endif
        if(isFound)
            return;
        if( bdeep + edeep > 8 )
            break;
        segNum(btmp,bval);
        segNum(etmp,eval);
        ///這裏就比較鬱悶了,對於每個棋子都要展開,
        ///對於每個棋子的移動都要判斷是否符合規矩
        ///其實rear代表着隊列裏面的節點數,我們從節點少的開始展開。
        for(int i = 0 ; i < 4 ; i++)   ///四個棋子
        {
            //      memcpy(btmp1,btmp,sizeof(btmp));
            //      memcpy(etmp1,etmp,sizeof(etmp));

            for(int j = 0 ; j < 4 ; j++)  ///四個方向
            {
                memcpy(btmp1,btmp,sizeof(btmp));
                memcpy(etmp1,etmp,sizeof(etmp));
                if(isFound) break;
                btmp1[2*i] = btmp[2*i] + dx[j];
                btmp1[2*i+1] = btmp[2*i+1] + dy[j];
                ///開始節點,x,y的移動
                etmp1[2*i] = etmp[2*i] + dx[j];
                etmp1[2*i+1] = etmp[2*i+1] + dy[j];
                ///最終節點,x,y的移動
                if ( checkMove(btmp1,btmp,2*i,j) )
                {
                    bval1 = getNum(btmp1);
                    if(insert_begin(bval1,bdeep+1))
                    {
                        bque[brear] = bval1;
                        _bdeep[brear] = bdeep + 1;
                        brear++;
                    }

                }
                if ( checkMove(etmp1,etmp,2*i,j))
                {
                    eval1 = getNum(etmp1);
                    if(insert_end(eval1,edeep+1))
                    {
                        eque[erear] = eval1;
                        _edeep[erear] = edeep + 1;
                        erear++;
                    }
                }
            }
        }
        bfront++;
        efront++;///bdeep++;edeep++;
    }

}
int main()
{
#ifdef INPUT
    freopen("b:\\acm\\poj1198\\input.txt","r",stdin);
    freopen("b:\\acm\\poj1198\\output1.txt","w",stdout);
#endif
#ifdef DBG1
    int a = 1;
#endif
    while(scanf("%d",&bs[0])  != EOF)
    {
#ifdef DBG1
        printf("Process condition : %d\n",a);
        a++;
#endif
        for(int i = 1 ; i < 8 ; i++)
        {
            scanf("%d",&bs[i]);
        }
        for(int i = 0 ; i < 8 ; i++)
        {
            scanf("%d",&es[i]);
        }
        Solve();
        if (isFound)
        {
            printf("YES\n");
        }
        else
        {
            printf("NO\n");
        }
    }
#ifdef INPUT
    fclose(stdin);
    fclose(stdout);
#endif
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章