您的位置:首页 > 其它

poj1077-不作此题人生不完整~经典搜索题

2014-08-29 14:56 357 查看
这题可不是简单的迷宫搜索之类的,我用STL的单向bfs搜索就超时了,于是我迫不得已手写队列,AC,接下来要尝试双向和A*
首先是单向BFS:



300ms还可以啊,我以为会是七八百毫秒的

这个是A星算法的:



估价函数我自己想的,所以没那些人那么快
/*******单向BFS********
****会用康托函数以及保存路径就行**/
#include<iostream>
#include<string>
#include<queue>
#define M 900000
using namespace std;
int fac[] = { 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880 };
int vis[M],pre[M],flag;
char ans[M],way[M];
int dir[]={-1,1,3,-3}; //l,r,u,d
char dc[4]={'l','r','d','u'};
typedef struct
{
int x; //这个就是八数码的状态值
int t; //步数
int place; //x在九位数字中的位置
char str[10]; //那个状态时的字符串
}puzzle;

puzzle p[M]; //手动创建队列
int front;
int rear;

void EnQ(puzzle pp) //入队
{
p[rear]=pp;
rear=(rear+1)%M;
}

puzzle DeQ( ) //出队
{
puzzle pp;
pp=p[front];
front=(front+1)%M;
return pp;
}

int order(char *s, int n) //利用康托展开,求字符串的状态值
{
int i, j, temp, num;
num = 0;
for (i = 0; i < n-1; i++)
{
temp = 0;
for (j = i + 1; j < n; j++)
if (s[j] < s[i])
temp++;
num += fac[s[i]-1-'0'] * temp;
}
return num;
}

void bfs(char s[],int start)
{
int i,y;
char temp;
memset(vis,0,sizeof(vis));
front=rear=0;
puzzle pp,ppp;
pp.x=order(s,9);
pp.t=0;
pp.place=start;
strcpy(pp.str,s);
vis[pp.x]=1;
EnQ(pp);
while(front!=rear)
{
pp=DeQ();
if(pp.x==0)
{
flag=1;
int a=pp.x;
for(i=pp.t;i>=1;i--) //照着之前储存的信息一直回到起点
{
ans[i]=way[a];
a=pre[a];
}
for(i=1;i<=pp.t;i++)
printf("%c",ans[i]);
cout<<endl;
return ;
}

for(i=0;i<4;i++)
{
ppp=pp;
y=ppp.place+dir[i]; //要变换的位置
if((i==0&&y%3==2)||(i==1&&y%3==0)||y<0||y>8)
continue;

temp=ppp.str[pp.place];
ppp.str[ppp.place]=ppp.str[y];
ppp.str[y]=temp; //交换操作,改变字符串
y=order(ppp.str,9); // 再把y=那个hash值

if(vis[y]==0)
{
pre[y]=ppp.x; //这个点的前一位赋值
ppp.x=y;
vis[y]=1;
way[y]=dc[i];
ppp.t++;
ppp.place+=dir[i];
EnQ(ppp);
}

}

}

}

int main()
{
int i,j;
char s[10];
char str,start;
flag=0;
for(i=0;i<9;)
{
scanf("%c",&str);
if(str!=' ')
{
if(str=='x')
{
s[i]='9';
start=i;
}
else
s[i]=str;
i++;
}
}
s[9]='\0';
bfs(s,start);
if(flag==0)
cout<<"unsolvable"<<endl;

}

<pre name="code" class="cpp">/*******不知道真假的A星算法*********
****f=g(已走步数)+h(每一个格子回到原位所需的步数)+**/
#include<iostream>
#include<string>
#include<queue>
#include<cmath>
#define M 900000
using namespace std;
int fac[] = { 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880 };
int vis[M],pre[M],flag;
char ans[M],way[M];
int dir[]={-1,1,3,-3}; //l,r,u,d
char dc[4]={'l','r','d','u'};
char *ss="123456789";
struct puzzle
{
int x; //这个就是八数码的状态值
int place; //x在九位数字中的位置
int f; //总代价
int g; //已用代价
int h; //估计代价
char str[10]; //那个状态时的字符串
bool operator < (const puzzle &a) const
{
if(f==a.f)
return h>a.h; //优先选择f值小的,如果f值相等有点选择h值小的
else return f>a.f;
}
};

int order(char *s, int n) //利用康托展开,求字符串的状态值
{
int i, j, temp, num;
num = 0;
for (i = 0; i < n-1; i++)
{
temp = 0;
for (j = i + 1; j < n; j++)
if (s[j] < s[i])
temp++;
num += fac[s[i]-1-'0'] * temp;
}
return num;
}

int FindH(char *s) //h=每一个格子回到原位所需的步数
{
int sum=0,m;
for(int i=0;i<9;i++)
if(s[i]!=ss[i])
{
m=abs(s[i]-'0'-1-i);
sum+=m/3+m%3;
}
return sum;
}

void bfs(char s[],int start)
{
int i,y;
char temp;
memset(vis,0,sizeof(vis));
priority_queue<puzzle>q;
struct puzzle pp,ppp;
pp.x=order(s,9);
pp.g=0;
pp.place=start;
strcpy(pp.str,s);
vis[pp.x]=1;
pp.h=FindH(pp.str);
pp.f=pp.h+pp.g;
q.push(pp);
while(!q.empty())
{
pp=q.top(); //先出队的都是f值小的
q.pop();
if(pp.x==0)
{
flag=1;
int a=pp.x;
for(i=pp.g;i>=1;i--) //照着之前储存的信息一直回到起点
{
ans[i]=way[a];
a=pre[a];
}
for(i=1;i<=pp.g;i++)
printf("%c",ans[i]);
cout<<endl;
return ;
}

for(i=0;i<4;i++)
{
ppp=pp;
y=ppp.place+dir[i]; //要变换的位置
if((i==0&&y%3==2)||(i==1&&y%3==0)||y<0||y>8)
continue;

temp=ppp.str[pp.place];
ppp.str[ppp.place]=ppp.str[y];
ppp.str[y]=temp; //交换操作,改变字符串
y=order(ppp.str,9); // 再把y=那个hash值

if(vis[y]==0)
{
pre[y]=ppp.x; //这个点的前一位赋值
ppp.x=y;
vis[y]=1;
way[y]=dc[i];
ppp.place+=dir[i];
ppp.g++;
ppp.h=FindH(ppp.str);
ppp.f=ppp.h+ppp.g;
q.push(ppp);
}

}

}

}

int main()
{
int i,j;
char s[10];
char str,start;
flag=0;
for(i=0;i<9;)
{
scanf("%c",&str);
if(str!=' ')
{
if(str=='x')
{
s[i]='9';
start=i;
}
else
s[i]=str;
i++;
}
}
s[9]='\0';
bfs(s,start);
if(flag==0)
cout<<"unsolvable"<<endl;

}



                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  bfs A星