#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;
}
【POJ1198 Solitaire 】 思路+解題報告+測試數據生成器
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.