题目链接:
https://cn.vjudge.net/problem/POJ-1077
(根据我自己的理解写的,有错误的地方希望大家可以指正一下,非常感谢!)
IDA*解法:
什么是IDA*算法?
IDA*是基于深搜的基础上的一种优化算法。
对于这个题来说,由于深搜算出最佳方案需要耗费很多的时间,所以我们就从假定最优解开始算起,若搜索不出来这个结果,就将假定最优解加一再搜一次,直到搜到与当前假定最优解相同的结果。搜索过程中要加上很重要的剪枝,即IDA*的核心:当前的曼哈顿距离+已走过的深度<=当前假定最优解。
如何判断八数码问题可解?
在这里不详细解释了,大致说一下。利用逆序数的奇偶性来判断,按行的顺序将矩阵接起来,变为一行数,计算逆序数,忽略 0。若为偶数则可解,否则不可解(必要不充分条件);网上很多博客解释,在这里推荐一个: https://blog.csdn.net/u010398265/article/details/50987577
IDA*代码:
A*解法:
A*是基于广搜的基础上的优化算法。
启发式搜索。也需要计算曼哈顿距离。用一个优先队列,以当前深度+当前曼哈顿距离的值小的优先;用逆序数判断是否有解。
(根据我自己的理解写的,有错误的地方希望大家可以指正一下,非常感谢!)
IDA*解法:
什么是IDA*算法?
IDA*是基于深搜的基础上的一种优化算法。
对于这个题来说,由于深搜算出最佳方案需要耗费很多的时间,所以我们就从假定最优解开始算起,若搜索不出来这个结果,就将假定最优解加一再搜一次,直到搜到与当前假定最优解相同的结果。搜索过程中要加上很重要的剪枝,即IDA*的核心:当前的曼哈顿距离+已走过的深度<=当前假定最优解。
什么是曼哈顿距离呢?
曼哈顿距离其实就是初始状态到目标状态的最短距离。举个例子,一个2*2的矩阵:3 1 2 4,要想将其变为1 2 3 4,它的曼哈顿距离应该是将初始状态中每个位置上的数到它的目标状态的位置的最短距离之和,3的位置是(0,0),而它的目标状态位置为(1,0),所以3到目标状态位置的最短距离应该是1,以此类推可算出曼哈顿距离。为了便于计算,在执行代码时,将' x ' 变为‘ 0 ,此题在求曼哈顿距离时要注意忽略 0 。
什么是当前假定最优解?
其实就是初始的曼哈顿距离。每搜索一次时,这个值会加一。
如何判断八数码问题可解?
在这里不详细解释了,大致说一下。利用逆序数的奇偶性来判断,按行的顺序将矩阵接起来,变为一行数,计算逆序数,忽略 0。若为偶数则可解,否则不可解(必要不充分条件);网上很多博客解释,在这里推荐一个: https://blog.csdn.net/u010398265/article/details/50987577
IDA*代码:
#include<stdio.h>
#include<string.h>
#include<math.h>
int Map[4][4];
int max1,min1;
int start_x,start_y;
int flag;
int c[4][2]= {-1,0,0,1,0,-1,1,0};
int path[10000];
int goal[10],start[10];
int HMD()//曼哈顿距离;
{
int i,j,num=0;
for(i=0; i<3; i++)
for(j=0; j<3; j++)
if(Map[i][j]==0)
continue;
else
num+=fabs((Map[i][j]-1)/3-i)+fabs((Map[i][j]-1)%3-j);
return num;
}
void start_xyz()//0的初始位置;
{
int i,j;
for(i=0; i<3; i++)
for(j=0; j<3; j++)
if(Map[i][j]==0)
{
start_x=i;
start_y=j;
return ;
}
}
void swap(int *a,int *b)//交换函数;
{
int t;
t=*a;
*a=*b;
*b=t;
}
void dfs(int x,int y,int s,int last_step)//搜索过程;
{
if(flag)
return ;
if(s==max1)//与当前假定最优解相同;
{
int l=HMD();
if(l==0)//与目标状态相同;
{
min1=s;
flag=1;
}
return ;
}
for(int i=0; i<4; i++)
{
if(last_step+i==3&&s>0)
continue;
int dx=x+c[i][0];
int dy=y+c[i][1];
if(dx<0||dy<0||dx>=3||dy>=3)
continue;
swap(&Map[dx][dy],&Map[x][y]);//先交换位置,再判断是否符合条件;
if(HMD()+s<=max1&&!flag)//IDA*;
{
path[s]=i;
dfs(dx,dy,s+1,i);
if(flag)
return ;
}
swap(&Map[dx][dy],&Map[x][y]);//回溯;
}
}
int check()//判断是否有解;
{
int i,j,num1=0,num2;
for(i=0; i<8; i++)
for(j=i+1; j<8; j++)
{
if(start[j]<start[i])
num1++;
}
if(num1%2)
return 0;
else
return 1;
}
int main()
{
char a[110];
char dis[4]= {'u','r','l','d'};
int i,j;
gets(a);
int k=0;
int sum=-1;
for(i=0; i<strlen(a); i++)
{
if(a[i]==' ')
continue;
sum++;
if(a[i]=='x')
Map[sum/3][sum%3]=0;
if(a[i]>='1'&&a[i]<='8')
{
Map[sum/3][sum%3]=a[i]-'0';
start[k++]=a[i]-'0';
}
}
start_xyz();
int ans=check();//判断是否有解;
if(!ans)
{
printf("unsolvable\n");
return 0;
}
max1=HMD();//初始假定最优解;
if(max1==0)
{
printf("\n");
return 0;
}
flag=0;
while(!flag)
{
dfs(start_x,start_y,0,0);
if(!flag)
max1++;
}
for(i=0; i<min1; i++)//输出路径方向;
printf("%c",dis[path[i]]);
printf("\n");
return 0;
}
A*解法:
A*是基于广搜的基础上的优化算法。
启发式搜索。也需要计算曼哈顿距离。用一个优先队列,以当前深度+当前曼哈顿距离的值小的优先;用逆序数判断是否有解。
A*代码:
#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
#include<math.h>
using namespace std;
int c[4][2]= {0,1,1,0,-1,0,0,-1};
char D[4]= {'r','d','u','l'};
int book[3700000];
int C[9]= {1,1,2,6,24,120,720,5040,40320};
struct node
{
int pos;
int step;
int state[10];
int HMD;
int cantor;
bool operator < (const node h)const
{
return step+HMD>h.step+h.HMD;
}
};
struct yun
{
int Node;
int dis;
} path[3700000];
int is_solve(int a[])
{
int i,j,ans=0;
for(i=0; i<8; i++)
for(j=i+1; j<9; j++)
{
if(a[i]==9||a[j]==9)continue;
if(a[j]<a[i])
ans++;
}
if(ans&1)
return 1;
else
return 0;
}
int hmd(int ma[])
{
int ans=0,i;
for(i=0; i<9; i++)
{
if(ma[i]==9)
continue;
ans+=fabs((ma[i]-1)/3-i/3)+fabs((ma[i]-1)%3-i%3);
}
return ans;
}
int Cantor(int a[])
{
int i,j,l,ans=0;
for(i=0; i<8; i++)
{
l=0;
for(j=i+1; j<9; j++)
if(a[j]<a[i])
l++;
ans+=C[8-i]*l;
}
return ans;
}
void A_star(int pos,int a[])
{
int i;
priority_queue<node> Q;
node st,en;
for(i=0; i<9; i++)
st.state[i]=a[i];
st.pos=pos;
st.HMD=hmd(st.state);
st.cantor=Cantor(st.state);
st.step=0;
Q.push(st);
while(Q.size())
{
st=Q.top();
Q.pop();//printf("Cantor: %d Step: %d Pos: %d\n",st.cantor,st.step,st.pos);
if(st.cantor==0)
{
int k=0;
int p[10000];
for(i=1; i<=st.step; i++)
{
p[i]=path[k].dis;
k=path[k].Node;
}
for(i=st.step;i>=1;i--)
printf("%c",D[p[i]]);
printf("\n");
return ;
}
int x=st.pos/3;
int y=st.pos%3;
for(i=0; i<4; i++)
{
int dx=x+c[i][0];
int dy=y+c[i][1];
int dz=dx*3+dy;
if(dx<0||dy<0||dx>2||dy>2)
continue;
for(int j=0; j<9; j++)
en.state[j]=st.state[j];
swap(en.state[dz],en.state[st.pos]);
// printf("%d \n",dz);
int kk=Cantor(en.state);
// printf("KK %d KK\n",kk);
if(book[kk])
continue;
// printf("%d****\n",i);
book[kk]=1;
en.cantor=kk;
en.pos=dz;
en.step=st.step+1;
// printf("%d**>>\n");
en.HMD=hmd(en.state);
path[kk].dis=i;
path[kk].Node=st.cantor;
Q.push(en);
}
}
}
int main()
{
char str[100];
gets(str);
int puzzle[10],pos;
int k=0,i;
for(i=0; i<strlen(str); i++)
{
if(str[i]!=' ')
{
if(str[i]=='x')
{
puzzle[k++]=9;
pos=k-1;
}
else
puzzle[k++]=str[i]-'0';
}
}
int is=is_solve(puzzle);
if(is)
printf("unsolvable\n");
else
A_star(pos,puzzle);
}
康托展开+bfs():
康拓展开判重+bfs();
代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#include<iostream>
using namespace std;
int flag;
int b[10];
int h[10]={1,1,2,6,24,120,720,5040,40320,362880};
int book[370000];
int path[370000],dis[370000],ans[370000];
char d[4]={'u','r','d','l'};
int c[4][2]={-1,0,0,1,1,0,0,-1};
struct yun
{
int num[10];
int s;
int pos;
};
int cantor(int aa[])
{
int i,j,l,ans=0;
for(i=0;i<8;i++)
{
l=0;
for(j=i+1;j<9;j++)
{
if(aa[j]<aa[i])l++;
}
ans+=h[8-i]*l;
}
return ans;
}
void bfs(int k)
{
int i;
queue<yun> Q;
yun st,en;
st.pos=k;
for(i=0;i<9;i++)
st.num[i]=b[i];
st.s=0;
Q.push(st);
while(Q.size())
{
st=Q.front();
Q.pop();
if(cantor(st.num)==0)
{
int start=0;
for(i=st.s;i>0;i--)
{
ans[i]=dis[start];
start=path[start];
}
for(i=1;i<=st.s;i++)
printf("%c",d[ans[i]]);
printf("\n");
flag=1;
return ;
}
int x=st.pos/3,y=st.pos%3;
for(i=0;i<4;i++)
{
int dx=x+c[i][0];
int dy=y+c[i][1];
int dz=dx*3+dy;
if(dx<0||dy<0||dx>=3||dy>=3)continue;
for(int j=0;j<9;j++)
en.num[j]=st.num[j];
swap(en.num[dz],en.num[st.pos]);
int kk=cantor(en.num);
if(book[kk])continue;
en.s=st.s+1;
en.pos=dz;
book[kk]=1;
path[kk]=cantor(st.num);
dis[kk]=i;
Q.push(en);
}
}
}
int main()
{
int i,e;
char A[100];
gets(A);
int k=0;
for(i=0;i<strlen(A);i++)
{
if(A[i]!=' ')
{
if(A[i]=='x')
{
b[k++]=9;
e=k-1;
}
else
{
b[k++]=A[i]-'0';
}
}
}
flag=0;
memset(book,0,sizeof(book));
book[cantor(b)]=1;
bfs(e);
if(!flag)
printf("unsolvable\n");
}