Problem Address:http://poj.org/problem?id=1077
Problem Address:http://acm.hdu.edu.cn/showproblem.php?pid=1043
【前言】
第一次写八数码问题。
这份代码写得也是够残的。
还好效率不是很低。
HDU的数据明显比POJ的强。而且HDU里有初末状态相同的情况,而POJ没有。
这也是后来改成双向A*之后在HDU上狂WA的原因。
提交了20多次之后才发现真相= =
【思路】
典型的八数码问题。
九宫格中有1-8的数字,空出一位用于数字的移动。求从一个状态转移到另一个状态的路径。
具体的存储方式可以到网上搜一下。
以下简单介绍几种应用于八数码问题的搜索算法。
DFS:
由于不知道步数,所以用DFS是不可取的。
BFS:
从初始状态开始,每一步向四个方向扩展。直到达到末状态。
简单的BFS使用的空间很大,时间也很大,当步数增加时节点数膨胀很快。
因为,就八数码问题,一般的BFS不太可取。
双向BFS:
从初状态和末状态同时开始扩展。扩展方式与一般BFS相同。
直到两者有交点时停止查找。
相比于一般的BFS,双向BFS无论是在空间还是时间方面,都有很大的提升。
A*启发式搜索:
利用启发式函数 f'() = a*g'() + b*h'(),g'()表示当前以使用代价(可用步数表示),h'()表示达到目标还需花费的代价(可用manhattan距离或者相同位置不同数字的个数表示)。
启发式搜索相对于前面的搜索提升是巨大的。访问的结点很少,空间和时间的使用也因此很少。
可以这样看,BFS都是A*的一种特殊形式。
当b=0且a!=0时,f'() = a*g'(),即只于结点所耗步数有关,即为一般的BFS。
所以,通过改变a和b的值可以在一定程度上提升搜索效率。
双向A*:
A*与双向BFS的结合。
【代码】
这份代码是双向A*,但是通过改变里面的参数可以实现BFS、双向BFS、A*等。
#include
#include
using namespace std;
const int maxhash = 400000;
int start, end = 123456789;
int le[9] = {1,10,100,1000,10000,100000,1000000,10000000,100000000};
int te[9] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320};
int manhattan[9][9] = {
{0,1,2,1,2,3,2,3,4},
{1,0,1,2,1,2,3,2,3},
{2,1,0,3,2,1,4,3,2},
{1,2,3,0,1,2,1,2,3},
{2,1,2,1,0,1,2,1,2},
{3,2,1,2,1,0,3,2,1},
{2,3,4,1,2,3,0,1,2},
{3,2,3,2,1,2,1,0,1},
{4,3,2,3,2,1,2,1,0}};
int re[9];
struct HASH
{
bool visited;
int value;
int pre;
char op;
bool inqueue;
int g;
int h;
bool opposite;
}hash[maxhash];
struct cmp
{
bool operator()(const int &a, const int &b)
{
int fa = hash[a].g + 10*hash[a].h;
int fb = hash[b].g + 10*hash[b].h;
return fa>fb;
}
};
char get_opposite(char op)
{
switch(op)
{
case 'u':
return 'd';
case 'd':
return 'u';
case 'l':
return 'r';
case 'r':
return 'l';
default:
return 'x';
}
}
priority_queue, cmp> q;
void init_hash()
{
int i;
for (i=0; i=0; i--)
{
if (i+1=0; i--)
{
temp[i] = x%10;
x /= 10;
}
int sum = 0;
for (i=1; i<8; i++)
{
for (j=0; j=0; i--)
{
if (i+1=0; i--)
{
if (i+1=0; i--)
{
temp[i] = x%10;
x /= 10;
}
for (i=1; i<8; i++)
{
k = 0;
for (j=0; jhash[pre].g+1)
{
hash[hx].g = hash[pre].g + 1;
hash[hx].op = op;
hash[hx].pre = pre;
if (!hash[hx].inqueue)
{
hash[hx].inqueue = true;
q.push(hx);
}
}
}
return false;
}
bool expand(int t)
{
int j;
int temp = t%10;
int ht = get_hash(t);
hash[ht].inqueue = false;
if (temp>3)
{
j = move('u', t);
if (valid(j, 'u', ht)) return true;
}
if (temp%3!=0)
{
j = move('r', t);
if (valid(j, 'r', ht)) return true;
}
if (temp<7)
{
j = move('d', t);
if (valid(j, 'd', ht)) return true;
}
if (temp%3!=1)
{
j = move('l', t);
if (valid(j, 'l', ht)) return true;
}
return false;
}
int main()
{
char str[100];
int i, j;
int t;
while(cin.getline(str, 100))
{
start = 0;
for (i=0,j=0; str[i]!='\0'; i++)
{
if (str[i]!=' ')
{
if (str[i]=='x')
{
t = j + 1;
}
else
{
start = start*10 + (str[i]-'0');
j++;
}
}
}
start = start*10 + t;
if (!check_even(start))
{
printf("unsolvable\n");
continue;
}
if (start==end)
{
printf("\n");
continue;
}
init_hash();
init_rank(start);
while(!q.empty()) q.pop();
valid(start, 'x', -1);
valid(end, 'x', -1);
while(!q.empty())
{
int ht = q.top();
t = hash[ht].value;
q.pop();
if (expand(t)) break;
}
}
return 0;
}