您的位置:首页 > 大数据 > 人工智能

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

2012-03-16 18:43 543 查看
#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: