您的位置:首页 > 其它

poj 1077 Eight (bfs A* IDA*)

2011-06-06 21:07 375 查看
第一次写A*算法 写的有点晕,思路还是很明显很清晰的 就是处理起来有些麻烦 ,自己写了一个堆,可以说是优先队列,网上也有看到用STL的priority_queue的 以后研究下.

今天写了一天,毕竟第一次接触A*算法,第一次写,算是我的处女作,不过结果没让我失望 1A了,结果16Ms 还挺快,提交第二次就成0ms了,这就看运气. F=G+H, 就是A*算法的精华所在了 每次都取F最小的,这样是最有可能到达结果的, 因为在程序运行过程中 要更新那些已经在堆中的元素的F值,所以自己写堆也就方便了这一点,不用浪费空间,把重复的状态再加入优先队列里.因为更改了堆中的某个节点,就只要像新插入一个节点那样,跟他的父节点比较,把自己提升到正确的位置,当然,前提是要知道自己要更新的节点在堆中的什么位置,这也就要position[k] 来记录状态k在堆中的位置, 改变位置时要更新position的值.

总之,今天还是有很大收获的...........................不过以后如果再写,估计还要花上半天时间,自己的思维经常乱啊...ps:今天端午节... orz..我是菜鸟...

还有一双向广搜 方法:::http://blog.csdn.net/dizem/archive/2009/08/12/4436663.aspx

 
#include <iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
#define N 370000
#define M 10
int fac[] = { 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880 };
struct Node
{
int val,h,steps;              //val即f , h为估值 ,steps为g  .  f=g+h;
int pos;           //0的位置
int  id;             //id  状态值 即哈希值  通过get_hash函数得到的 与状态一一对应的值
char p[M];        //当前状态;

};
int mark[10][2];          //用于求估值,即 值i应该在( mark[i][0],mark[i][1])的位置; 3*3的坐标
char reflect[]="urdl";   //求方向
void print_ans(int t);    //输出结果
int heapsize=1;            //堆的当前大小;
Node priority_que
;              //堆  优先队列
int position
; int direction
; int pre
; int used
; //position[k] id值为k的状态在堆中的位置
int dirx[]={-1,0,1,0};  int diry[]={0,1,0,-1};    //direction[k] 存0-3表示id为k的状态是由其father pre[k]
//按照direction[k]的方向变换得到的  used[k]为0 1 2分别代表
int res_id;                                //状态k没出现过 ,已经在堆中 和已经LOCK(pop)了
int  bfs();

int get_val(char *p);                                //  计算估值的函数
int get_hash(char *p);                              //计算id的函数
//堆的操作
void heap_shift_down(int pos);
void heap_shift_up(Node tar,int pos);
void heap_insert(Node n,int &heapsize);
Node heap_pop();
void swap(int x,int y);
int main()
{
freopen("in.txt","r",stdin);
for(int i=1;i<9;i++)
{
mark[i][0]=(i-1)/3;
mark[i][1]=(i-1)%3;
}
// priority_que从1开始
for(int i=0;i<9;i++)
{
cin>>priority_que[1].p[i];
if(priority_que[1].p[i]=='x')
{
priority_que[1].pos=i;  priority_que[1].p[i]='0';
}
}
char res[]="123456780";
res_id=get_hash(res);
if(bfs())
print_ans(res_id);
else cout<<"unsolvable"<<endl;

}

int  bfs()
{
int rank;
int id=get_hash(priority_que[1].p);
position[id]=1;
pre[id]=-1;  used[id]=1;
if(id==res_id) return id;
priority_que[1].id=id;
priority_que[1].steps=0;
priority_que[1].h=get_val(priority_que[1].p);
priority_que[1].val=priority_que[1].h;
while(heapsize>0)
{
Node tmp=heap_pop();
used[tmp.id]=2;                      //标记为 LOCK
int tx=tmp.pos/3;                    //0位置坐标
int ty=tmp.pos%3;
for(int i=0;i<4;i++)                    //四个方向
{
Node newnode;                    //newnode是pop出来的状态tmp按四个方向
int x=tx+dirx[i];                    //拓展出来的新状态
int y=ty+diry[i];
if(x>=0&&x<3&&y>=0&&y<3){
newnode=tmp;
int tt=x*3+y;
newnode.p[tmp.pos]=newnode.p[tt];
newnode.p[tt]='0';
newnode.pos=tt;
rank=get_hash(newnode.p);
newnode.id=rank;  newnode.steps++;
if(used[rank]==0)
{
used[rank]=1;
direction[rank]=i;
pre[rank]=tmp.id;
newnode.h=get_val(newnode.p);
newnode.val=newnode.h+ newnode.steps;
heap_insert(newnode,heapsize);
if(used[res_id]==1)
return  res_id;
}
else if(used[rank]==1)
{
int pos=position[rank];  //找到状态在 堆中的位置,更新val, steps值以及pre等
int step=priority_que[pos].steps;
if(step>tmp.steps+1)
{
priority_que[pos].steps= tmp.steps+1;
priority_que[pos].val=priority_que[pos].h+priority_que[pos].steps;
pre[rank]=tmp.id;
direction[rank]=i;
heap_shift_up(priority_que[pos],pos);   //小顶堆中的值被Decrease之后
//要用shift_up维护堆,把它调到适当的
//位置
}
}
}
}

}
return 0;
}

Node heap_pop()
{
Node t=priority_que[1];
priority_que[1]=priority_que[heapsize];
position[priority_que[1].id]=1;
heapsize--;
if(heapsize>0)
{
heap_shift_down(1);
}
return t;
}

void heap_shift_up(Node tar,int pos)
{
int cur=pos;
while(cur/2>=1&&priority_que[cur/2].val>tar.val)
{
priority_que[cur]=priority_que[cur/2];
position[priority_que[cur].id]=cur;                //更新position
cur/=2;
}
priority_que[cur]=tar;
position[priority_que[cur].id]=cur;
return ;
}

void heap_insert(Node n,int &heapsize)
{
heapsize++;
priority_que[heapsize]=n;
heap_shift_up(n,heapsize);
return ;
}

void heap_shift_down(int pos)
{
int l=2*pos; int r=l+1;
int min_pos=pos;
if(l<=heapsize&&priority_que[l].val<priority_que[min_pos].val)
min_pos=l;
if(r<=heapsize&&priority_que[r].val<priority_que[min_pos].val)
min_pos=r;
if(min_pos!=pos){
swap(min_pos,pos);
heap_shift_down(min_pos);
}
}

void swap(int x,int y)             //在元素交换过程中要更新position;
{
Node tmp=priority_que[x];
priority_que[x]=priority_que[y];
position[priority_que[x].id]=x;
priority_que[y]=tmp;
position[priority_que[y].id]=y;
}

int get_hash(char *p)
{
int cnt=0;
int total=0;
for(int i=0;i<9;i++){
cnt=0;
for(int j=i+1;j<9;j++)
{
if(p[j]<p[i]) cnt++;
}
total+=fac[8-i]*(cnt);
}
return total;
}

int get_val(char *p)                  //估值函数
{
int x,y; int t;int total=0;
for(int i=0;i<9;i++)
{
x=i/3; y=i%3;
t=p[i]-'0';
if(t!=0)
{
total+=abs(x-mark[t][0])+abs(y-mark[t][1]);
}
}
return total;
}

void print_ans(int t)
{
char  tt[1000];
int k=0;
while(pre[t]!=-1)
{
tt[k++]=reflect[direction[t]];
t=pre[t];
}
for(int x=k-1;x>=0;x--)
cout<<tt[x];
cout<<endl;
return ;
}


 

 

 

IDA*  刚刚看了一下, 貌似是迭代加深搜索 加了一个估值函数,具体也没怎么了解 照着别人的程序写的.

只能说数据太....没有unsolvable的情况  否则肯定TLE了, 搜索深度到40就已经慢的不行了,更别说100 跳出循环了....

#include <iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
#define N 370000
#define M 10
struct Node
{
char p[M];
int h;
int pos;
};
int dirx[]={-1,0,1,0};
int diry[]={0,1,0,-1};
int mark[10][2];
char  dir[]="urdl";
int get_h(char *p);
Node node;
int IDA(Node & p,int h,int pre);
int max_height;
int direction[100];
int cnt=0;
int main()
{
freopen("in.txt","r",stdin);
for(int i=1;i<9;i++)
{
mark[i][0]=(i-1)/3;
mark[i][1]=(i-1)%3;
}
for(int i=0;i<9;i++)
{
cin>>node.p[i];
if(node.p[i]=='x')
{
node.pos=i;node.p[i]='0';
}
}
node.h=get_h(node.p);
int done=0;
for(int i=node.h;i<100;i++)
{
max_height=i;
if(IDA(node,0,-1))
{
done=1;break;
}
}
cnt-=1;
if(done)
{
while(cnt>=0) cout<<dir[direction[cnt--]];
cout<<endl;
}
else  cout<<"unsolvable"<<endl;

}

int IDA(Node & p,int h,int pre)
{
if(p.h==0)
{
return 1;
}
if(h+p.h>max_height)
return 0;
for(int i=0;i<4;i++)
{
if(abs(pre-i)==2)
continue;
int pos=p.pos;
N
9b62
ode tmp=p;
int tmpx=pos/3+dirx[i];
int tmpy=pos%3+diry[i];
if(tmpx<0||tmpx>=3||tmpy<0||tmpy>=3)
continue;
int k=3*tmpx+tmpy;
tmp.p[pos]=tmp.p[3*tmpx+tmpy];
tmp.p[3*tmpx+tmpy]='0';
tmp.pos=3*tmpx+tmpy;
int val=p.p[k]-'0';
if((i==0||i==2)&&abs(tmpx-mark[val][0])>abs(pos/3-mark[val][0]))
tmp.h=p.h-1;
else if((i==1||i==3)&&abs(tmpy-mark[val][1])>abs(pos%3-mark[val][1]))
tmp.h=p.h-1;
else tmp.h=p.h+1;
if(IDA(tmp,h+1,i))
{
direction[cnt++]=i;
return 1;
}

}
return 0;
}

int get_h(char *p)
{
int x,y; int t;int total=0;
for(int i=0;i<9;i++)
{
x=i/3; y=i%3;
t=p[i]-'0';
if(t!=0)
{
total+=abs(x-mark[t][0])+abs(y-mark[t][1]);
}
}
return total;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  insert struct 算法 up