64,701
社区成员
发帖
与我相关
我的任务
分享
15数码的IDA*算法
来源是CSDN的download中心
请自己去搜索IDA*算法.
"
现在机器解16码问题基本上采用松弛子问题启发式+结果数据库来做
单纯的Hamilton距离作启发式搜索深度大的话很难出解
"
"
有很多无解的情况,可以用置换群理论中置换的奇偶性来快速判断有无解!
"
// IDA*(迭代式深度搜索)
// 把SIZE改成4就可以变成15数码问题
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<conio.h>
#define SIZE 4
typedef char board[SIZE][SIZE];
board target = {1 ,2 ,3, 4,
12, 13, 14, 5 ,
11, 0, 15, 6 ,
10, 9, 8, 7}; // 目标状态,改成15数码的话要同时改掉
board start;
long add[4][2]={-1,0,0,1,1,0,0,-1};
/*************************估价函数*****************************/
long targetplace[SIZE*SIZE][2]; // 这个估价函数是用来剪枝的
long CAL_H(board & node) {
long i,j;
long re = 0;
for (i=0; i<SIZE; i++) for (j=0; j<SIZE; j++) if (node[i][j]) {
re += abs(i - targetplace[node[i][j]][0])
+ abs(j - targetplace[node[i][j]][1]);
}
return re;
}
/***************************************************************/
bool can_solve() { // 搜索前判断是否可解
long i,j,k1,k2;
for (i=0; i<SIZE; i++) for (j=0; j<SIZE; j++) {
if (start[i][j]==0) {
start[i][j] = SIZE*SIZE;
k1 = (SIZE-1-i) + (SIZE-1-j);
}
if(target[i][j]==0){
target[i][j] = SIZE*SIZE;
k2 = (SIZE-1-i) + (SIZE-1-j);
}
}
for (i=0; i<SIZE*SIZE; i++) for (j=i+1; j<SIZE*SIZE; j++) {
if (start[i/SIZE][i%SIZE] > start[j/SIZE][j%SIZE]) k1++;
if (target[i/SIZE][i%SIZE] > target[j/SIZE][j%SIZE]) k2++;
}
for (i=0; i<SIZE; i++) for (j=0; j<SIZE; j++) {
if (start[i][j]==SIZE*SIZE) start[i][j]=0;
if (target[i][j]==SIZE*SIZE) target[i][j]=0;
}
return (k1%2)==(k2%2);
}
void out_board(board state,long step) {
long i,j;
printf("STEP %ld:\n", step);
for(i=0;i<SIZE;i++){
for(j=0;j<SIZE;j++){
printf("%ld ", state[i][j]);
}
printf("\n");
}
printf("\n");
}
void output(long dep, char path[]) { // 输出答案
long i,j,x1,y1,x0,y0;
board state;
memcpy(state, start, sizeof(state));
out_board(state,0);
for(i=0;i<SIZE;i++)for(j=0;j<SIZE;j++)if(state[i][j]==0)x0=i,y0=j;
for (i=0; i<dep; i++) {
x1=x0+add[path[i]][0];
y1=y0+add[path[i]][1];
state[x0][y0] = state[x1][y1];
state[x1][y1] = 0;
x0 = x1, y0 = y1;
out_board(state,i+1);
}
printf("The minimum number of steps is %ld.\n", dep);
}
/***********************************************************************************/
long ans;
char path[100000];
bool ida(board & node, long x0, long y0, long dep, long d, long h) {
long i,j,k,x1,y1,h1;
if (memcmp(node, target, sizeof(target))==0) {
output(dep, path);
return 1;
}
if (dep==ans) return 0;
board node1;
for (i=0; i<4; i++) {
if (((i%2)==(d%2)) && i!=d) continue;
x1 = x0 + add[i][0];
y1 = y0 + add[i][1];
if (x1<0||y1<0||x1==SIZE||y1==SIZE) continue;
memcpy(node1, node, sizeof(node1));
node1[x1][y1] = 0;
node1[x0][y0] = node[x1][y1];
if (i==3 && y1<targetplace[node[x1][y1]][1]) h1=h-1;
else if (i==1 && y1>targetplace[node[x1][y1]][1]) h1=h-1;
else if (i==0 && x1<targetplace[node[x1][y1]][0]) h1=h-1;
else if (i==2 && x1>targetplace[node[x1][y1]][0]) h1=h-1;
else h1=h+1;
if (h1+dep+1>ans) continue; // 根据估价值(h1+dep)
// 和假定的解的步数(ans)来剪枝
path[dep] = i;
if (ida(node1,x1,y1,dep+1,i,h1)) return 1;
}
return 0;
}
int main() {
long i,j,k,x0,y0;
long cs;
//scanf("%ld", &cs);
cs = 1;
printf("input=\n");
while (cs--) {
for (i=0;i<SIZE;i++)for(j=0;j<SIZE;j++) {
scanf("%ld",&k);
start[i][j] = k;
if (k==0) { x0=i; y0=j; }
}
for (k=1,i=0; i<SIZE; i++) for (j=0; j<SIZE; j++) {
targetplace[target[i][j]][0] = i;
targetplace[target[i][j]][1] = j;
}
if (!can_solve()) { printf("This puzzle is not solvable.\n"); continue; }
i = -1;
j = CAL_H(start);
for (ans=j; ; ans+=1) {
if (ida(start,x0,y0,0,i,j)) {
break;
}
}
getch();
}
return 0;
}
附:
判断是否有解的代码
#include <iostream>
#include <cmath>
using namespace std;
int temp[2][10005];
int result;
int Merge(int* from, int* to, int l_len, int r_len)
{
int i, j, k;
for (i = j = k =0;i<l_len&&j<r_len;)
if (from[i] < from[j+l_len]) to[k++]=from[i++], result+=j;
else to[k++]=from[l_len+j++];
while(i<l_len) to[k++]=from[i++], result+=j;
while(j<r_len) to[k++]=from[l_len+j++];
}
int inv(int n,int a[])
{
int l, start, i;
int ret = 0;
int* t = temp[1];
for (l = 1; l < n; l<<=1)
{
for (start = 0; start+l*2<=n; start+=l*2)
Merge(a+start, t+start, l, l);
if (start+l<n) Merge(a+start, t+start, l, n-1-(start+l)+1);
else for (;start<n;++start) t[start ] = a[start];
l*=2;
for (start = 0; start+l*2<=n; start+=l*2)
Merge(t+start, a+start, l, l);
if (start+l<n) Merge(t+start, a+start, l, n-1-(start+l)+1);
else for (;start<n;++start) a[start] = t[start];
}
}
char buff[10240];
int main()
{
int n;
while (scanf("%d\n", &n) == 1)
{
int off;
int idx = 0;
for (int i = 0; i < n; ++i)
{
int pos = 0;
gets(buff);
for (int j = 0; j < n - 1; ++j)
{
int t = 0;
while (buff[pos] != ' ') t = t *10+buff[pos++]-48;
++pos;
if (t == 0)
{
off = abs(i-n+1) + abs(j-n+1);
t = 1000000000;
}
temp[0][idx++] = t;
}
int t = 0;
while (buff[pos])t = t *10+buff[pos++]-48;
++pos;
if (t == 0)
{
off = abs(i-n+1);
t = 1000000000;
}
temp[0][idx++] = t;
}
result = 0;
inv(n*n, temp[0]);
if ((result + off) % 2 == 0) puts("YES");
else puts("NO");
}
return 0;
}
// denshanfa.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "doublegrade.h"
bool no_result(STATE start, STATE end)
{
sort(start.m_array, start.m_array + AEEAY_SIZE);
sort(end.m_array, end.m_array + AEEAY_SIZE);
return !(start == end);
}
//两个状态不同棋子数
int get_distince(const STATE& src, const STATE& desc)
{
int distince = 0;
for (int i = 0; i < HIGHTH; i++)
{
for (int j = 0; j < WITHLEN; j++)
{
if (src.m_array[i * WITHLEN + j] != desc.m_array[i * WITHLEN + j])
{
distince++;
}
}
}
return distince + src.m_generation - 1;
}
bool is_nearer(const P_STATE& left, const P_STATE& right)
{
return left->m_distince < right->m_distince;
}
void init_state(char *filename, char *array)
{
FILE *fp = fopen(filename, "r");
if (fp == NULL)
{
cerr << "can not open file " << filename << endl;
return;
}
int tmp;
for (size_t i = 0; i < HIGHTH; i++)
{
for (size_t j = 0 ; j < WITHLEN; j++)
{
fscanf(fp, "%d", &tmp);
array[i * WITHLEN + j] = tmp;
}
}
}
int domain(int argc, char* argv[])
{
P_NODE_DEQUE up_open_tab;
P_NODE_DEQUE down_open_tab;
P_NODE_DEQUE substate;
P_NODE_MAP close_tab;
const char UP_FIRST_FIND = 1;
const char UP_SECOEND_FIND = 2;
const char HAD_UP = UP_FIRST_FIND | UP_SECOEND_FIND;
const char DOWN_FIRST_FIND = 4;
const char DOWN_SECOEND_FIND = 8;
const char HAD_DOWN = DOWN_FIRST_FIND | DOWN_SECOEND_FIND;
char star_state_array[HIGHTH * WITHLEN] =
{
2, 15, 0, 3,
4, 10, 8, 5,
12, 9, 6, 11,
13, 1, 7, 14
};
char end_state_array[HIGHTH * WITHLEN] =
{
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 0
};
/*
char star_state_array[HIGHTH * WITHLEN] =
{
1, 2, 3,
4, 5, 6,
7, 0, 8
};
char end_state_array[HIGHTH * WITHLEN] =
{
1, 2, 3,
4, 5, 6,
7, 8, 0
};
*/
init_state("start.txt", star_state_array);
init_state("end.txt", end_state_array);
P_STATE stare_state = new STATE(star_state_array);
P_STATE end_state = new STATE(end_state_array);
P_STATE state, up_state, down_state;
if (no_result(*stare_state, *end_state))
{
cout << "no result" << endl;
return 0;
}
stare_state->m_father = NULL;
stare_state->m_generation = 1;
stare_state->m_distince = 0;
stare_state->m_distince = get_distince(*stare_state, *end_state);
end_state->m_father = NULL;
up_open_tab.push_back(stare_state);
close_tab[stare_state] |= UP_FIRST_FIND;
down_open_tab.push_back(end_state);
close_tab[end_state] |= DOWN_FIRST_FIND;
bool findend = false;
if (*end_state == *stare_state)
{
up_state = stare_state;
down_state = end_state;
findend = true;
}
while( up_open_tab.size() != 0 && down_open_tab.size() != 0 && !findend)
{
if (down_open_tab.size() > up_open_tab.size()) //状态数小的表优先搜索
{
DEBUG_COUT(cout << "open_tab.size() = " << up_open_tab.size() << endl);
state = up_open_tab.front();
up_open_tab.pop_front();
P_NODE_MAP_ITER it = close_tab.find(state);
//已正向遍历过的结点不再处理
if (it->second == UP_SECOEND_FIND)
{
substate.clear();
}
else
{
//生成子节点
get_next(substate, *state);
}
//对于每一个子节点判断是否已在反向遍历中出现过
DEBUG_COUT(cerr << __FILE__ << ":" << __LINE__ << endl);
for (size_t i = 0; i < substate.size(); i++)
{
//cout << "------------" << i << "--------------" << endl;
//substate[i]->show();
DEBUG_COUT(cerr << __FILE__ << ":" << __LINE__ << endl);
P_NODE_MAP_ITER it = close_tab.find(substate[i]);
if (it == close_tab.end())
{
up_open_tab.push_back(substate[i]);
close_tab[substate[i]] = UP_FIRST_FIND;
}
else
if ( (it->second & HAD_DOWN) > 0 )
{
DEBUG_COUT(cerr << __FILE__ << "*************find had down***************" << __LINE__ << endl);
up_state = substate[i];
down_state = it->first;
findend = true;
break;
}
DEBUG_COUT(cerr << __FILE__ << ":" << __LINE__ << endl);
}
//cout << "***************************************" << endl;
}
else
{
DEBUG_COUT(cout << "open_tab.size() = " << down_open_tab.size() << endl);
state = down_open_tab.front();
down_open_tab.pop_front();
P_NODE_MAP_ITER it = close_tab.find(state);
if (it->second == DOWN_SECOEND_FIND)
{
substate.clear();
}
else
{
get_next(substate, *state);
}
DEBUG_COUT(cerr << __FILE__ << ":" << __LINE__ << endl);
for (size_t i = 0; i < substate.size(); i++)
{
//cout << "------------" << i << "--------------" << endl;
//substate[i]->show();
DEBUG_COUT(cerr << __FILE__ << ":" << __LINE__ << endl);
P_NODE_MAP_ITER it = close_tab.find(substate[i]);
if (it == close_tab.end())
{
down_open_tab.push_back(substate[i]);
close_tab[substate[i]] = DOWN_FIRST_FIND;
}
else
if ( (it->second & HAD_UP) > 0 )
{
DEBUG_COUT(cerr << __FILE__ << "*************find had up***************" << __LINE__ << endl);
up_state = it->first;
down_state = substate[i];
findend = true;
break;
}
DEBUG_COUT(cerr << __FILE__ << ":" << __LINE__ << endl);
}
//cout << "***************************************" << endl;
}
}
if (findend)
{
cout << "******************find the result*********************" << endl;
size_t i = 1;
STATE *pstate = down_state.get()->m_father;
vector< STATE * > ve_pstates;
while (pstate != NULL)
{
ve_pstates.push_back(pstate);
pstate = pstate->m_father;
}
for (size_t n = ve_pstates.size(); n != 0; n--)
{
cout << "******************step " << i++ << "*********************" << endl;
ve_pstates[n - 1]->show();
}
pstate = up_state.get();
while (pstate != NULL)
{
cout << "******************step " << i++ << "*********************" << endl;
pstate->show();
pstate = pstate->m_father;
}
}
else
{
cout << "no result" << endl;
}
cout << "end domain" << endl;
return 0;
}
int main(int argc, char *argv[])
{
RUNTIME(domain, (argc, argv));
return 0;
}