您的位置:首页 > 其它

POJ 1077 Eight【八数码问题】

2011-03-02 21:45 501 查看
http://poj.org/problem?id=1077
八数码问题:
由1,2,3,4,5,6,7,8,x组成一个3*3的矩阵,如
1 2 3
4 x 5
6 7 8
其中x可与其上,下,左,右相邻的元素互换,
现问从给出状态出发到达以下状态:
1 2 3
4 5 6
7 8 x
需要对x进行怎样的位移操作,输出x的最少位移信息,
若状态不可达,输出unsolvable

分析:
1.一个很容易的想法,即BFS,
2.用康托展开将每个状态转化为整数,即可略过已访问点
3.再用优先队列加以优化
4.其实可以用A*加以优化,f(x) = g(x)+h(x),h(x)为当前状态中x所在位置到右下角位置的哈密尔顿距离(不过实际中没遇到)
5.如果是单case的话,用以上即可水过,
但若是多case,复杂度会过高,超时。
6.解决多case的方法是,在预处理中从目标状态出发BFS,记录所有可达状态信息。
这样,对于输入的任何一种状态,便可直接输出答案(又邪恶了吧。。)

PS:
问题在BFS过程略过已搜索过的状态
纠结了很久之后,终于还是不忍去网上搜了一下,
呵呵,居然让我发现还有康托展开这么个好东东!
关于康托展开,百度百科上说得还是比较清楚的:http://baike.baidu.com/view/437641.htm
简单说一下:
将x抽象为数字9,对于每个状态,可映射为{1,2,3,4,5,6,7,8,9}的一个排列。
根据康托展开,即将具体的排列转化为一个数字,即可保存其状态

这个该死的康托,还是用了一定的时间去搞的,可惜,我只知道怎样把一个排列变成数字,把数字变成排列是怎么也搞不来,
所以,偷偷小懒,干脆把数组扔进了节点里,邪恶了。。。

因为POJ上是单case的,所以果断从给出的状态BFS直到搜到最终状态为止,就这样邪恶的水过。。
ZOJ和HDU貌似很是不给面子,多case,果断超时。。。。
回来继续研究,赫,不让我怎么搞,我就倒着搜呗,于是想到了在预处理中从目标点BFS一次,记录下所有可达状态,O(∩_∩)O哈,就这么水水地又过了。。

Code BFS:

View Code

#include<iostream>
#include<math.h>
#include<stdio.h>
usingnamespace std;
constint SIZE =3;
char board[SIZE][SIZE];
//启发函数,除去x之外到目标网格的距离和
int goal_state[9][2]={{0,0},{0,1},{0,2},{1,0},{1,1},{1,2},{2,0},{2,1},{2,2}};
int step[4][2] = {{-1,0},{0,-1},{0,1},{1,0}};//ulrd
char op[5] ="ulrd";

int h(char board[][SIZE])
{
int cost =0;
int i,j;
for(i=0;i<SIZE;i++)
for(j=0;j<SIZE;j++)
{
if(board[i][j]!=SIZE*SIZE)
cost += abs(i - goal_state[board[i][j]-1][0]) +
abs(j - goal_state[board[i][j]-1][1]);
}
return cost;
}
inline int min(int a,int b)
{
return a<b?a:b;
}
char solution[1000];
int bound;//上界
bool ans;//是否找到答案
//DFS返回next_bound
int DFS(int x,int y,int dv,char pre_move)
{
int hv = h(board);
if(hv+dv>bound)
return hv+dv;
if(hv ==0)
{
ans =true;
return dv;
}

int next_bound = 1e9;
int i;
for(i=0;i<4;i++)
{
if(i+pre_move ==3)//与上一步相反的移动
continue;
int nx = x+step[i][0];
int ny = y+step[i][1];
if(0<=nx&&nx<SIZE&&0<=ny&&ny<SIZE)
{
solution[dv]=i;
swap(board[x][y],board[nx][ny]);
int new_bound = DFS(nx,ny,dv+1,i);
if(ans)
return new_bound;
next_bound = min(next_bound,new_bound);
swap(board[x][y],board[nx][ny]);
}
}
return next_bound;
}

void IDA_star(int sx,int sy)
{
ans =false;
bound = h(board);//初始化代价
while(!ans&&bound<=100)//上限
{
bound = DFS(sx,sy,0,-10);
}
}
int main()
{
int sx,sy;
char c;
int i,j;
for(i=0;i<SIZE;i++)
for(j=0;j<SIZE;j++)
{
cin>>c;
if(c=='x')
{
board[i][j]=SIZE*SIZE;
sx = i;
sy = j;
}
else
board[i][j] = c -'0';
}

IDA_star(sx,sy);

if(ans)
{
for(i=0;i<bound;i++)

cout<<op[solution[i]];

}else
cout<<"unsolvable";
return0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: