菜鸟就要老老实实重新学起:
八数码:
很经典的搜索问题,写这个练练搜索。
八数码问题就是给出一个3*3的矩阵其中有1~8数字和一个空格‘x’,可以移动周围的数字到这个空格上,要求某种排列恢复到{
{1,2,3},{4,5,6},{7,8,x}}形式的移动方法。
由大神的八数码八境界想自己实现一下 http://www.cnblogs.com/goodness/archive/2010/05/04/1727141.html
一、暴力BFS+STL
就是直接暴力bfs所有的询问,string储存当前状态,vector<int>储存当前路径,map判重,好写,但时间感人。
代码:
#define N 512345
char s[101];
struct node
{
string str;
vector<int>res;
int index;
};
map<string,int> mp;
vector<int>res;
bool bfs(string ss)
{
char c;
queue<node> q;
while(!q.empty())q.pop();
node g,h;
g.str="12345678x";g.res.clear();g.index=8;
q.push(g);
while(!q.empty())
{
g=q.front();q.pop();
if(g.str==ss)
{
res=g.res;
return true;
}
h=g;
if((h.index+1)%3!=0)
{
c=h.str[h.index];h.str[h.index]=h.str[h.index+1];h.str[h.index+1]=c;
h.index++;
h.res.push_back(4);
if(mp[h.str]==0)
{
mp[h.str]=true;
q.push(h);
}
}
h=g;
if(h.index%3!=0)
{
c=h.str[h.index];h.str[h.index]=h.str[h.index-1];h.str[h.index-1]=c;
h.index--;
h.res.push_back(3);
if(!mp[h.str])
{
mp[h.str]=true;
q.push(h);
}
}
h=g;
if(h.index<6)
{
c=h.str[h.index];h.str[h.index]=h.str[h.index+3];h.str[h.index+3]=c;
h.index+=3;
h.res.push_back(2);
if(!mp[h.str])
{
mp[h.str]=true;
q.push(h);
}
}
h=g;
if(h.index>2)
{
c=h.str[h.index];h.str[h.index]=h.str[h.index-3];h.str[h.index-3]=c;
h.index-=3;
h.res.push_back(1);
if(!mp[h.str])
{
mp[h.str]=true;
q.push(h);
}
}
}
return false;
}
int main()
{
int i,j,k,kk,t,x,y,z;
while(scanf("%s",s)!=EOF)
{
mp.clear();
for(i=1;i<9;i++)
scanf("%s",s+i);
string ss(s);
if(bfs(ss))
for(i=res.size()-1;i>=0;i--)
{
if(res[i]==1)printf("d");
if(res[i]==2)printf("u");
if(res[i]==3)printf("r");
if(res[i]==4)printf("l");
}
else
printf("unsolvable");
printf("\n");
}
return 0;
}
二、暴力BFS+hash判重
与上一方法基本相同,就是减少stl的使用,改用char[]存状态,用康托展开计算全排列数值从而得到哈希值判重。
能够有效缩减时间,但是询问多时尤其是在无解时耗时依然较多。
关于康托展开:http://blog.youkuaiyun.com/kopyh/article/details/48377291
代码:
#define N 512345
char ss[10];
struct node
{
char str[10];
vector<int>res;
int index,hashnum;
};
vector<int>res;
bool vis[N];
int fac[] = {1,1,2,6,24,120,720,5040,40320};
int over;
int KT(char ss[])
{
int i, j, t, sum;
int s[10];
for(i=0;i<9;i++)
{
if(ss[i]=='x')
s[i]=0;
else
s[i]=ss[i]-'0';
}
sum = 0;
for (i=0; i<9; i++)
{
t = 0;
for (j=i+1; j<9; j++)
if (s[j] < s[i])
t++;
sum += t*fac[9-i-1];
}
return sum+1;
}
bool bfs(char ss[])
{
char c;
queue<node> q;
while(!q.empty())q.pop();
over = KT(ss);
node g,h;
for(int i=0;i<8;i++)
g.str[i]=i+1+'0';
g.str[8]='x';g.str[9]='\0';
g.res.clear();g.index=8;
q.push(g);
while(!q.empty())
{
g=q.front();q.pop();
if(KT(g.str)==over)
{
res=g.res;
return true;
}
h=g;
if((h.index+1)%3!=0)
{
c=h.str[h.index];h.str[h.index]=h.str[h.index+1];h.str[h.index+1]=c;
h.index++;
h.res.push_back(4);
int t=KT(h.str);
if(!vis[t])
{
vis[t]=true;
q.push(h);
}
}
h=g;
if(h.index%3!=0)
{
c=h.str[h.index];h.str[h.index]=h.str[h.index-1];h.str[h.index-1]=c;
h.index--;
h.res.push_back(3);
int t=KT(h.str);
if(!vis[t])
{
vis[t]=true;
q.push(h);
}
}
h=g;
if(h.index<6)
{
c=h.str[h.index];h.str[h.index]=h.str[h.index+3];h.str[h.index+3]=c;
h.index+=3;
h.res.push_back(2);
int t=KT(h.str);
if(!vis[t])
{
vis[t]=true;
q.push(h);
}
}
h=g;
if(h.index>2)
{
c=h.str[h.index];h.str[h.index]=h.str[h.index-3];h.str[h.index-3]=c;
h.index-=3;
h.res.push_back(1);
int t=KT(h.str);
if(!vis[t])
{
vis[t]=true;
q.push(h);
}
}
}
return false;
}
int main()
{
int i,j,k,kk,t,x,y,z;
while(scanf("%s",ss)!=EOF)
{
memset(vis,false,sizeof(vis));
for(i=1;i<9;i++)
scanf("%s",ss+i);
if(bfs(ss))
for(i=res.size()-1;i>=0;i--)
{
if(res[i]==1)printf("d");
if(res[i]==2)printf("u");
if(res[i]==3)printf("r");
if(res[i]==4)printf("l");
}
else
printf("unsolvable");
printf("\n");
}
return 0;
}
三、暴力BFS+hash判重 +打表
与上一方法基本相同,就是改成一次BFS所有可能进行打表,时间可以保持在200ms内解决问题。
代码:
#define N 512345
char ss[10];
struct node
{
char str[10];
vector<int>res;
int index,num;
};
vector<int>res[N];
bool vis[N];
int fac[] = {1,1,2,6,24,120,720,5040,40320};
int over;
int ans[N];
int KT(char ss[])
{
int i, j, t, sum;
int s[10];
for(i=0;i<9;i++)
{
if(ss[i]=='x&#