//A*算法, 启发函数:采用数字位不同数
#pragma warning(disable:4786)
![]()
#include <algorithm>
![]()
#include <cstdio>
![]()
#include <set>
![]()
#include <utility>
![]()
#include <ctime>
![]()
#include <cassert>
![]()
#include <cstring>
![]()
using namespace std;
/*
![]()
item记录搜索空间中一个结点
![]()
state 记录用整数形式表示的8数码格局
![]()
blank 记录当前空格位置,主要用于程序优化,扩展时可不必在寻找空格位置
![]()
g, h 对应g(n), h(n)
![]()
pre 记录当前结点由哪个结点扩展而来
![]()
*/
![]()
struct item
![]()
{
![]()
int state;
![]()
int blank;
![]()
int g;
![]()
int h;
![]()
int pre;
![]()
};
const int MAXSTEPS = 100000;
![]()
const int MAXCHAR = 100;
![]()
char buf[MAXCHAR][MAXCHAR];
![]()
//open表
![]()
item open[MAXSTEPS];
![]()
int steps = 0;
![]()
//closed表,已查询状态只要知道该状态以及它由哪个结点扩展而来即可,用于输出路径
![]()
//每次只需得到对应f值最小的待扩展结点,用堆实现提高效率
![]()
pair< int, int> closed[MAXSTEPS];
//读入,将8数码矩阵格局转换为整数表示
![]()
bool read(pair< int, int> &state)
![]()
{
![]()
// 第一行
![]()
if (!gets(buf[0]))
![]()
return false;
![]()
// 第二行
![]()
if (!gets(buf[1]))
![]()
return false;
![]()
// 第三行
![]()
if (!gets(buf[2]))
![]()
return false;
![]()
//判断获得了几个字符 ,不包括'\0'
![]()
assert(strlen(buf[0]) == 5 && strlen(buf[1]) == 5 && strlen(buf[2]) == 5);
![]()
state.first = 0;
![]()
for ( int i = 0, p = 1; i < 3; ++i)
![]()
{
![]()
for ( int j = 0; j < 6; j += 2)
![]()
{
![]()
if (buf[i][j] == ' ')
![]()
state.second = i * 3 + j / 2;
![]()
else
![]()
state.first += p * (buf[i][j] - '0');
![]()
p *= 10;
![]()
}
![]()
}
![]()
//是倒着排的 First:5 0【空格位置】 7 4 6 1 3 8 2 ;Second:7 (记录空格的位置)
![]()
return true;
![]()
}
/*
![]()
int calculate(int current, int target)
![]()
{
![]()
int cnt = 0;
![]()
for (int i = 0; i < 9; ++i)
![]()
{
![]()
if ((current % 10 != 0)&& (current % 10) != (target % 10))
![]()
++cnt;
![]()
current /= 10;
![]()
target /= 10;
![]()
}
![]()
return cnt;
![]()
}
![]()
*/
//计算当前结点距目标的距离, 包括空格的位置
![]()
int calculate( int current, int target)
![]()
{
![]()
int c[9], t[9];
![]()
int i, cnt = 0;
![]()
//位置
![]()
for (i = 0; i < 9; ++i)
![]()
{
![]()
c[current % 10] = t[target % 10] = i;
![]()
current /= 10;
![]()
target /= 10;
![]()
}
![]()
for (i = 1; i < 9; ++i)
![]()
cnt += abs(c[i] / 3 - t[i] / 3) + abs(c[i] % 3 - t[i] % 3);
![]()
return cnt;
![]()
}
//open表中结点间选择时的规则 f(n) = g(n) + h(n), 由小到大排
![]()
class cmp
![]()
{
![]()
public: inline bool operator()(item a, item b)
![]()
{
![]()
return a.g + a.h > b.g + b.h;
![]()
}
![]()
};
//将整数形式表示转换为矩阵表示输出
![]()
void pr( int state)
![]()
{
![]()
memset(buf, ' ', sizeof(buf));
![]()
for ( int i = 0; i < 3; ++i)
![]()
{
![]()
for ( int j = 0; j < 6; j += 2)
![]()
{
![]()
if (state % 10)
![]()
buf[i][j] = state % 10 + '0';
![]()
state /= 10;
![]()
}
![]()
buf[i][5] = '\0';
![]()
puts(buf[i]);
![]()
}
![]()
}
//用于判断当前空格是否可以向对应方向移动
![]()
inline bool suit( int a, int b)
![]()
{
![]()
return (a >= 0 && a < 3 && b >= 0 && b < 3);
![]()
}
//递归输出搜索路径路径
![]()
void path( int index)
![]()
{
![]()
if (index == 0)
![]()
{
![]()
pr(closed[index].first);
![]()
puts("");
![]()
return;
![]()
}
![]()
path(closed[index].second);
![]()
pr(closed[index].first);
![]()
puts("");
![]()
++steps;
![]()
}
int main()
![]()
{
![]()
unsigned int t1 = clock();
![]()
freopen( "astar.in", "r", stdin);
![]()
freopen( "astar2.out", "w", stdout);
![]()
//记录扩展节点
![]()
set< int>states;
![]()
char tmp[100];
![]()
int i, x, y, a, b, nx, ny, end, next, index, kase = 0;
![]()
pair< int, int> start, target;
![]()
item head;
![]()
//4个方向移动时的偏移量--左 上 右 下
![]()
const int xtran[4] = {-1, 0, 1, 0};
![]()
const int ytran[4] = {0, 1, 0, -1};
![]()
const int p[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
![]()
while (read(start))
![]()
{
![]()
unsigned int t2 = clock();
![]()
printf( "Case %d:\n\n", ++kase);
![]()
//去除空行
![]()
gets(tmp);
![]()
read(target);
![]()
//去除空行
![]()
gets(tmp);
![]()
//初始化open表,将初始状态加入
![]()
open[0].state = start.first;
![]()
open[0].h = calculate(start.first, target.first);
![]()
open[0].blank = start.second;
![]()
open[0].pre = -1;
![]()
open[0].g = 0;
![]()
index = 0;
![]()
//将第一个状态插入set<int>中
![]()
states.insert(start.first);
![]()
//提取open表中f值最小元素放入closed表,并对该结点进行扩展
![]()
for (end = 1; end > 0; ++index)
![]()
{
![]()
assert(index < MAXSTEPS);
![]()
//临时存储---去除open table中f值最小的
![]()
head = open[0];
![]()
//放入closed表记录当前格局和由哪个结点扩展而来(该结点肯定已在closed表中)
![]()
closed[index].first = open[0].state;
![]()
closed[index].second = open[0].pre;
![]()
//从open表中删除该结点
![]()
pop_heap(open, open + end, cmp());
![]()
--end;
![]()
//得到结果,递归输出路径
![]()
if (head.state == target.first)
![]()
{
![]()
path(index);
![]()
break;
![]()
}
![]()
//转换为8位码图的响应位置
![]()
x = head.blank / 3;
![]()
y = head.blank % 3;
![]()
for (i = 0; i < 4; ++i)
![]()
{
![]()
//上 右 下 左
![]()
nx = x + xtran[i];
![]()
ny = y + ytran[i];
![]()
if (suit(nx, ny))
![]()
{
![]()
a = head.blank;
![]()
b = nx * 3 + ny;
![]()
//调换十进制表示整数对应两个数字位
![]()
next = head.state + ((head.state % p[a + 1]) / p[a] - (head.state % p[b + 1]) / p[b]) * p[b]
![]()
+ ((head.state % p[b + 1]) / p[b] - (head.state % p[a + 1]) / p[a]) * p[a];
![]()
//判断是否已经扩展过
![]()
if (states.find(next) == states.end())
![]()
{
![]()
//未扩展
![]()
states.insert(next);
![]()
open[end].pre = index;
![]()
open[end].blank = b;
![]()
open[end].state = next;
![]()
open[end].h = calculate(next, target.first);
![]()
open[end].g = head.g + 1;
![]()
++end;
![]()
push_heap(open, open + end, cmp());
![]()
}
![]()
}
![]()
}
![]()
}
![]()
if (end <= 0)
![]()
puts( "No solution");
![]()
else
![]()
{
![]()
printf( "Num of steps: %d\n", steps);
![]()
printf( "Num of expanded: %d\n", index);
![]()
printf( "Num of generated: %d\n", index + end);
![]()
printf( "Time consumed: %d\n\n", clock() - t2);
![]()
}
![]()
states.clear();
![]()
steps = 0;
![]()
}
![]()
printf( "Total time consumed: %d\n", clock() - t1);
![]()
return 0;
![]()
}