八数码问题

题意

给出一个九宫格(3*3),上面有1~8共八个数字块按某个顺序排列,而有一个空格,让你通过移动使它排列成12345678空.

普通版V1.0

Aizu - ALDS1_13_B 8 Puzzle

经典版的,不过只需要输出移动次数因此可能有什么高级解法,不过我还是按书的模板打的可输出路径版.

#include<bits/stdc++.h>
using namespace std;
const int dx[4]={0,0,-1,1},dy[4]={-1,1,0,0};
const char rd[4]={'u','d','l','r'};
struct gg{
    int mp[9];
    int space;
    string path;
    bool operator<(const gg &tmp)const
    {
        for(int i=0;i<=8;i++)
           {
            if(mp[i]!=tmp.mp[i])return mp[i]>tmp.mp[i];
           }
        return false;   
    }
};
bool ifok(gg a)
{
    for(int i=0;i<8;i++)
      if(a.mp[i]!=i+1)return false;
    return true;  
}
gg bfs(gg bg)
{
    queue<gg> q;gg now,tmp;int x,y;
    map<gg,bool>vis;
    vis[bg]=1;
    q.push(bg);
    while(!q.empty())
    {   
        now=q.front();q.pop();
        if(ifok(now))return now;
        x=now.space%3;y=now.space/3;
        for(int i=0;i<=3;i++)
           {
             tmp=now;
             if(x+dx[i]<0||x+dx[i]>2||y+dy[i]<0||y+dy[i]>2)continue;
             tmp.space=x+dx[i]+(y+dy[i])*3;
             swap(tmp.mp[x+y*3],tmp.mp[x+dx[i]+(y+dy[i])*3]);
             tmp.path+=rd[i];
             if(vis[tmp])continue;
             vis[tmp]=1;q.push(tmp);
           }
    }   
}
int main()
{
    gg bg,ans;
    for(int i=0;i<=8;i++)
       {
        scanf("%d",&bg.mp[i]);
        if(bg.mp[i]==0)bg.space=i;
       }   
    bg.path="";
    ans=bfs(bg);
    cout<<ans.path.length()<<endl;//话说aoj老是卡换行,没有就pe...
}

升级版V2.0

HDU - 1043 八数码

数据不只一组,因此每次搜会tle加mle…所以首先预处理,从结尾情况往回推出每一种情况的最短路径,然后O(1)查询就好了,注意因为是反推的,所以答案反着输出就行了.

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const short dx[4]={0,0,-1,1},dy[4]={-1,1,0,0};
const char rd[4]={'d','u','r','l'};
struct gg{
    short mp[9];
    short space;
    string path;
    bool operator<(const gg &tmp)const
    {
        for(short i=0;i<=8;i++)
           {
            if(mp[i]!=tmp.mp[i])return mp[i]>tmp.mp[i];
           }
        return false;   
    }
};map<gg,bool>vis;
void bfs(gg bg)
{   queue<gg> q;
    gg now,tmp;short x,y;
    vis[bg]=1;
    q.push(bg);
    while(!q.empty())
    {   
        now=q.front();q.pop();
        x=now.space%3;y=now.space/3;
        for(short i=0;i<=3;i++)
           {
             tmp=now;
             if(x+dx[i]<0||x+dx[i]>2||y+dy[i]<0||y+dy[i]>2)continue;
             tmp.space=x+dx[i]+(y+dy[i])*3;
             swap(tmp.mp[x+y*3],tmp.mp[x+dx[i]+(y+dy[i])*3]);
             tmp.path+=rd[i];
             if(vis[tmp])continue;
             vis[tmp]=1;q.push(tmp);
           }
    }        
}
int main()
{ 
    gg bg,ans;char c;string s;
    for(int i=0;i<8;i++)
      bg.mp[i]=i+1;
    bg.mp[8]=0;bg.space=8;bg.path="";bfs(bg);  
    while(~scanf(" %c",&c))
    {if(c=='x')bg.space=0,bg.mp[0]=0;
        else bg.mp[0]=c-'0';
     for(short i=1;i<=8;i++)
       {scanf(" %c",&c);
        if(c=='x')bg.space=i,bg.mp[i]=0;
        else bg.mp[i]=c-'0';}   
    bg.path="";
    map<gg,bool>::iterator pos=vis.find(bg);
    if(pos!=vis.end())
      {
        s=pos->first.path;
        reverse(s.begin(),s.end());
      }
    else s="unsolvable";
    cout<<s<<endl;
   }
}

终极版VMax.0

POJ - 1077 Eight

题面与之前相同,只有一组测试输出路径,不过貌似数据特别特别强大,之前1.0版和2.0版都过不了(tle)…没办法只能写了1.0的astar版(话说改改估计连15数码都可以水过了哈)

#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<map>
using namespace std;
const int dx[4]={0,0,-1,1},dy[4]={-1,1,0,0};
const char rd[4]={'u','d','l','r'};
int mdd[9][9];
struct gg{
    int mp[9],md;
    int space;
    string path;
    bool operator<(const gg &tmp)const
    {
        for(int i=0;i<=8;i++)
           {
            if(mp[i]!=tmp.mp[i])return mp[i]>tmp.mp[i];
           }
        return false;   
    }
};
struct state{
    gg g;
    int e;
    friend bool operator<(state a,state b)
    {
        return a.e>b.e;
    }
};
int getmd(gg g)
{
    int ret=0;
    for(int i=0;i<=8;i++)
        if(g.mp[i]!=0)ret+=mdd[i][g.mp[i]-1];
    return ret;
}
gg bfs(gg bg)
{
    priority_queue<state> q;gg now,tmp;int x,y;state tp,ne;
    map<gg,bool>vis;
    state init;
    init.g=bg;init.e=getmd(bg);
    q.push(init);
    while(!q.empty())
    {   
        tp=q.top();q.pop();now=tp.g;
        if(now.md==0)return now;
        vis[now]=1;
        x=now.space%3;y=now.space/3;
        for(int i=0;i<=3;i++)
           {
             if(x+dx[i]<0||x+dx[i]>2||y+dy[i]<0||y+dy[i]>2)continue;
             tmp=now;tmp.md-=mdd[x+dx[i]+(y+dy[i])*3][tmp.mp[x+dx[i]+(y+dy[i])*3]-1];
             tmp.md+=mdd[now.space][tmp.mp[x+dx[i]+(y+dy[i])*3]-1];
             tmp.space=x+dx[i]+(y+dy[i])*3;
             swap(tmp.mp[x+y*3],tmp.mp[x+dx[i]+(y+dy[i])*3]);
             tmp.path+=rd[i];
             if(vis[tmp])continue;
             ne.g=tmp;ne.e=tmp.path.length()+tmp.md;q.push(ne);
           }
    }   
  printf("unsolvable");  
}
int main()
{  //freopen("in.txt","r",stdin); 
   for(int i=0;i<=8;i++)
      for(int j=0;j<=8;j++)
      mdd[i][j]=abs(i/3-j/3)+abs(i%3-j%3);
    gg bg,ans;char c;
    for(int i=0;i<=8;i++)
       {
        scanf(" %c",&c);
        if(c=='x')bg.space=i,bg.mp[i]=0;
        else bg.mp[i]=c-'0';
       }   
    bg.path="";bg.md=getmd(bg);
    ans=bfs(bg);
    cout<<ans.path;
}

小总结:astar是bfs加强版,每次选取操作的元素是按一个函数f来搞的,而f是由一个当前操作数和一个估计还要操作数组成(估价函数h),这就使如果估价函数选的好可以让程序跑得飞起来,例如此处选的估价函数就是每个数到它应在位置的曼哈顿距离之和.

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值