八数码问题

来源:互联网 发布:2017暑运大数据报告 编辑:程序博客网 时间:2024/05/15 02:40

题意

给出一个九宫格(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),这就使如果估价函数选的好可以让程序跑得飞起来,例如此处选的估价函数就是每个数到它应在位置的曼哈顿距离之和.

原创粉丝点击