以前考虑过拼图问题的处理,可以考虑把下面的几个格子排好后,再采用类似八数码问题的处理排列上面的几个方块。
这里再回顾一下稍微基础一些的八数码问题的处理,
对于八数码问题这样的拼图处理,由于数量不是太大,(所有图形种类是181440种),可以采用广度优先遍历的方式,
如果需要频繁的查找,可以一次把所有的节点路径都找出来,
下面的处理,就是从目标图形开始,把所有的节点都遍历出来,使用了一个map保存每个图形对应的存储index,再查找每个节点的pre节点,直到终点(目标图形),就可以得到每条路径了,这样的方式得到的还是最短路径。我们也可以自己写个字典树结构来代替map。
#include <map>
using namespace std;
struct node{
int id;
int ops;//the operation from pre to it
int v[3][3];
int x;
int y;
int pre;
node* next;
void setValue(int id0, int x0, int y0, int p, int o) {
id = id0;
x = x0;
y = y0;
pre = p;
ops = o;
}
int gethash() {
return v[0][0] + 10*v[0][1] + 100*v[0][2]
+ 1000*v[1][0] + 10000*v[1][1] + 100000*v[1][2]
+ 1000000*v[2][0] + 10000000*v[2][1];
}
};
class List{
public:
node* head;
node* tail;
List() {
head = tail = NULL;
}
void add(node* a) {
if (tail == NULL)
{
tail = a;
head = a;
}
tail->next = a;
a->next = NULL;
tail = a;
}
void pop() {
head = head->next;
}
node* getHead() {
return head;
}
};
int target[3][3] = {{0, 1, 2}, {3,4,5}, {6,7,8}};
int dx[4] = {0, 0, -1, 1};
int dy[4] = {1, -1, 0, 0};
void cpArr(int from[3][3], int to[3][3], int x, int y, int mode) {
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
to[i][j] = from[i][j];
}
}
if (mode < 0)
{
return;
}
int x1 = x + dx[mode];
int y1 = y + dy[mode];
int tmp = to[y1][x1];
to[y1][x1] = 0;
to[y][x] = tmp;
}
node all[500000];
int _tmain(int argc, _TCHAR* argv[])
{
map<int, int> idx;
int ct = 0;
//add head;
List list;
all[0].setValue(0, 0, 0, -1, -1);
cpArr(target, all[0].v, 0, 0, -1);
int h = all[0].gethash();
idx[h] = 0;
list.add(&all[0]);
ct++;
node* p = list.getHead();
while (p != NULL)
{
//4 direction
for (int i = 0; i < 4; i++)
{
int x1 = p->x + dx[i];
int y1 = p->y + dy[i];
if (x1 >= 0 && x1 <= 2 && y1 >= 0 && y1 <= 2)
{
cpArr(p->v, all[ct].v, p->x, p->y, i);
h = all[ct].gethash();
if (idx.count(h) > 0)
{
continue;
}
//add new index
idx[h] = ct;
all[ct].setValue(ct, x1, y1, p->id, i);
list.add(&all[ct]);
ct++;
}
}
//
list.pop();
p = list.getHead();
}
//ct 181440
return 0;
}