这道题目不可能只用bfs就解决,因为这样效率太低了,跟八数码问题的A*算法如出一辙,使用启发式搜索,要估计当前状态至少还需要多少步才能到最终状态,这个估计值加上当前状态已经经历的步数就是决定优先队列中出队状态节点的权重值,这个值越小,越应该优先出队,如果这个值相等再比较当前已经走的步数,小的那个再出队,其实估计还需要多少步并不复杂,不需要推测地非常准,只需要大概估计剪枝效果就很明显了,不剪枝直接dfs肯定超时,其实只需要统计当前状态中的矩阵里面不在其应该在的位置的小方格的个数,那么要到最终的状态,这些小方格要到其应该到的位置,至少需要空格位置来替换它一次,所以这个还需要多少步的估计值使用上面说的方块的统计值就行了,虽然不精确,但是剪枝的效果已经可以达到要求了。虽然只是一点点改进,但是带来的效率的提升对比起直接bfs确实非常明显。
#include <stdio.h>
#include <queue>
#include <map>
#include <list>
#include <string.h>
using namespace std;
#define MAX_HASH 50000
char last_state[6][7];
void init()
{
strcpy(last_state[1], " 11111\0");
strcpy(last_state[2], " 01111\0");
strcpy(last_state[3], " 00 11\0");
strcpy(last_state[4], " 00001\0");
strcpy(last_state[5], " 00000\0");
}
struct state
{
char m[6][7];
int blank_i, blank_j;
int step;
int min_step; //最少还需多少步
};
void get_min_step(struct state &sta)
{
int i, j;
int sum;
sum = 0;
for(i=1; i<=5; i++)
{
for(j=1; j<=5; j++)
{
if(sta.m[i][j]!=' ' && sta.m[i][j]!=last_state[i][j])
sum += 1;
}
}
sta.min_step = sum;
}
bool operator < (const struct state &a, const struct state &b)
{
if(a.step+a.min_step > b.step+b.min_step)
return true;
else if(a.step+a.min_step < b.step+b.min_step)
return false;
else
{
if(a.step > b.step)
return true;
else
return false;
}
}
map<int, list<struct state> > hash_table;
priority_queue<struct state> pq;
unsigned int _hash(const struct state sta)
{
int i, j;
unsigned int v;
v = 1;
for(i=1; i<=5; i++)
{
for(j=1; j<-5; j++)
{
if(sta.m[i][j] == '1')
v = v*i*431 + j;
}
}
return v%MAX_HASH;
}
bool is_visited(const struct state &sta)
{
unsigned int hv;
bool same;
int i, j;
hv = _hash(sta);
if(hash_table.find(hv) == hash_table.end())
return false;
else
{
list<struct state> &l = hash_table[hv];
list<struct state>::iterator it;
for(it=l.begin(); it!=l.end(); it++)
{
same = true;
for(i=1; i<=5; i++)
for(j=1; j<=5; j++)
if(it->m[i][j] != sta.m[i][j])
{
same = false;
goto l1;
}
l1:
if(same)
return true;
else
continue;
}
}
return false;
}
void insert2hashtalbe(const struct state &sta)
{
unsigned int hv;
hv = _hash(sta);
hash_table[hv].push_back(sta);
}
bool is_last_state(const struct state &sta)
{
int i;
bool same;
same = true;
for(i=1; i<=5; i++)
{
if(strcmp(sta.m[i]+1, last_state[i]+1))
{
same = false;
break;
}
}
return same;
}
bool find_target;
int change[8][2] =
{
1, 2,
-1, 2,
1, -2,
-1, -2,
2, 1,
-2, 1,
2, -1,
-2, -1
};
void print_arr(const struct state &sta)
{
for(int i=1; i<=5; i++)
{
printf("%s\n", sta.m[i]+1);
}
printf("\n");
}
void bfs()
{
struct state sta_top, sta;
int from_i, from_j;
int i;
while(!pq.empty())
{
memcpy(&sta_top, &(pq.top()), sizeof(struct state));
pq.pop();
//printf("pop: step=%d\n", sta_top.step);
//print_arr(sta_top);
if(is_last_state(sta_top))
{
find_target = true;
printf("Solvable in %d move(s).\n", sta_top.step);
break;
}
for(i=0; i<8; i++)
{
memcpy(&sta, &sta_top, sizeof(struct state));
from_i = sta.blank_i+change[i][0];
from_j = sta.blank_j+change[i][1];
if(from_i>=1 && from_i<=5 && from_j>=1 && from_j<=5)
{
sta.m[sta.blank_i][sta.blank_j] = sta.m[from_i][from_j];
sta.m[from_i][from_j] = ' ';
sta.blank_i = from_i;
sta.blank_j = from_j;
sta.step ++;
get_min_step(sta);
if(!is_visited(sta) && (sta.step+sta.min_step) <= 10)
{
pq.push(sta);
insert2hashtalbe(sta);
}
}
}
}
}
void func(const struct state &sta)
{
while(!pq.empty()) pq.pop();
hash_table.clear();
find_target = false;
if(sta.step+sta.min_step<=10)
{
pq.push(sta);
insert2hashtalbe(sta);
}
bfs();
if(!find_target)
printf("Unsolvable in less than 11 move(s).\n");
}
char buffer[100];
int main(void)
{
int n, i, j;
struct state sta;
//freopen("input.dat", "r", stdin);
init();
gets(buffer);
sscanf(buffer, "%d", &n);
while(n--)
{
for(i=1; i<=5; i++)
gets(sta.m[i]+1);
for(i=1; i<=5; i++)
for(j=1; j<=5; j++)
{
if(sta.m[i][j] == ' ')
{
sta.blank_i = i;
sta.blank_j = j;
goto run_func;
}
}
run_func:
sta.step = 0;
get_min_step(sta);
func(sta);
}
return 0;
}