特来YM+学习A*算法,A*果然快啊,在pku上曾经写过一个BFS,300MS,去航电直优化的空间接TLE.用A*算法北大16MS,航电750MS,效率很高啊。当然我的A*写得还不是特别好,航电上有16MS AC那道题的,看来这个A*还有优化的空间。
A*采用启发式搜索的思维方式很值得借鉴!F=G+H
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdio>
using namespace std;
int const maxn=365000;//总状态数不超过362880
char s[12],t[12];
//FOR DIRECTION
int num[9]={2,3,2,3,4,3,2,3,2};//指示每个位置可以移动的方向数
int dirn[9][4]=
{
{1,2},
{1,2,3},
{2,3},
{0,1,2},
{0,1,2,3},
{0,2,3},
{0,1},
{0,1,3},
{0,3}
};
//end
int xy[9][2]={{0,0},{1,0},{2,0},{0,-1},{1,-1},{2,-1},{0,-2},{1,-2},{2,-2}};//存每个位置的坐标
int fa[maxn],cz[maxn];//cz是回溯时记录方向
int factor[8]={1,2,6,24,120,720,5040,40320};
int dist[10][10];//存第i个位置到第j个位置要走的步数
int v[maxn];//标记是否在OPEN表中
int goalcode;
int initzeropos;
struct node
{
int pos,g,h,code;//code is short for hashcode
char s[12];
bool operator<(node o)
{
return (g+h) < (o.g+o.h);
}
};
#define ele node//可以修改数据类型
struct MinHeap
{
ele *h;//heap数组
int Csize;//CurrentSize现在的容量
int Msize;//最大容量
void Down(int s,int e)//第s号位置的元素进行下渗,数组中最大的下标到e
{
int i=s,j=2*i+1;
ele t=h[i];
while(j<=e)
{
if(j<e&&h[j+1]<h[j])
j++;
if(t<h[j])
break;
else
{
h[i]=h[j];i=j;j=2*j+1;
}
}
h[i]=t;
}
void Up(int s)//start,上渗函数
{
int j=s,i=(j-1)/2;
ele t=h[j];
while(j)
{
if(h[i]<t) break;
else
{
h[j]=h[i];j=i;i=(i-1)>>1;
}
}
h[j]=t;
}
MinHeap(int n){Msize=n;h=new ele[Msize];Csize=0;}//构造函数
bool Insert(const ele &x)
{
if(Csize==Msize)
return false;
h[Csize]=x;
Up(Csize);
Csize++;
return true;
}
ele RemoveMin()
{
//v[h[0].code]=false;//记录
ele x=h[0];
h[0]=h[Csize-1];
Csize--;
Down(0,Csize-1);
return x;
}
ele GetMin(){return h[0];}
};
MinHeap H(maxn);
int GetDist(int s,int t)//计算两个位置之间的最小步数
{
int dx=abs(xy[s][0]-xy[t][0]);
int dy=abs(xy[s][1]-xy[t][1]);
return dx+dy;
}
int cal(char s[]) //计算全排列的哈希值(hashcode)
{
int i,j,cnt,res=0;
for(i=1;i<9;i++)
{
cnt=0;
for(j=0;j<i;j++)
if(s[j]>s[i])cnt++;
cnt*=factor[i-1];
res+=cnt;
}
return res;
}
int estimate(char str[])
{
int res=0,i,des;
for(i=0;i<9;i++)
{
if(str[i]!='0')
{
des=str[i]-'0'-1;
res+=dist[i][des];
}
}
return res;
}
bool check(char s[])//检测目标状态是否可达
{
int i,j,cnt,res=0;
for(i=1;i<9;i++)
{
cnt=0;
for(j=0;j<i;j++)
if(s[j]>s[i])cnt++;
res+=cnt;
}
for(i=0;i<9;i++)
{
if(s[i]=='0')
{
res+=dist[i][8];
break;
}
}
if((res%2)==0)
return true;
else return false;
}
int change(char s[],int op,int pos) //互换位置,返回换后的空格位置
{
int end;
if(op==0)end=pos-3;
else if(op==1)end=pos+1;
else if(op==2)end=pos+3;
else if(op==3)end=pos-1;
char t=s[pos];
s[pos]=s[end];
s[end]=t;
return end;//返回调整后空格的位置
}
void Astar(char s[])
{
H.Csize=0;//清空操作
node t;
t.pos=initzeropos;
t.g=0;
t.h=estimate(s);
t.code=cal(s);
strcpy(t.s,s);
v[t.code]=true;
cz[t.code]=0;
fa[t.code]=-1;
H.Insert(t);
//以上为初始化
while(H.Csize>0)
{
node tt=H.RemoveMin();
if(tt.code==goalcode)
{
int ans[1000];
int k=0,fp;
fp=tt.code;
while(fp!=t.code)
{
ans[k++]=cz[fp];
fp=fa[fp];
}
for(int i=k-1;i>=0;i--)
{
if(ans[i]==0)printf("u");
else if(ans[i]==1)printf("r");
else if(ans[i]==2)printf("d");
else if(ans[i]==3)printf("l");
}
printf("\n");
return;
}
int len=num[tt.pos];
for(int i=0;i<len;i++)
{
node x=tt;
x.pos=change(x.s,dirn[tt.pos][i],x.pos);
x.code=cal(x.s);
x.g++;
x.h=estimate(x.s);
if(!v[x.code])
{
v[x.code]=true;
fa[x.code]=tt.code;
cz[x.code]=dirn[tt.pos][i];
H.Insert(x);
}
}
}
}
int main()
{
int i,j;
strcpy(t,"123456780");
goalcode=cal(t);
for(i=0;i<9;i++)
for(j=0;j<9;j++)dist[i][j]=GetDist(i,j);
char str[50];
while(gets(str))
{
int len=strlen(str),pos=0;
memset(v,0,sizeof(v));
for(i=0;i<len;i++)
{
if(str[i]=='x')//空格部分用0代替
{
initzeropos=pos;
s[pos++]='0';
}
else if(str[i]>='1'&&str[i]<='8')s[pos++]=str[i];
}
s[9]='\0';
if(!check(s))printf("unsolvable\n");
else Astar(s);
}
return 0;
}
代码参考了:
http://www.cppblog.com/longzxr/archive/2010/07/05/92978.html#119349