【POJ1198 Solitaire 】 思路+解题报告+测试数据生成器

来源:互联网 发布:php微信公众号开发源码 编辑:程序博客网 时间:2024/05/21 22:30
#include <iostream>#include <cstring>#include <cstdio>#include <cstdlib>//#define DBG//#define INPUT//#define DBG1using 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;}