洛谷 P1379 八数码难题

来源:互联网 发布:周末网络国债理财申请 编辑:程序博客网 时间:2024/06/13 00:00

啊!!这一题算是BFS中的经典了,如果你不懂BFS的话,可以睡觉了~~~
现在请大家跳转题面

题目描述在3×3的棋盘上,摆有八个棋子,每个棋子上标有18的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。输入输出格式输入格式:输入初试状态,一行九个数字,空格用0表示输出格式:只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)输入输出样例输入样例#1:283104765输出样例#1:4

啊!!现在我们来分析一下思路
1.使用3*3的数组存储,操作十分简单,但会超时很多点,有兴趣的读者可以自行尝试一下;
2.程序中用3*3的二维数组表示布局比较直观,但在判断重复,判断是否达到目标方面,却给程序增加了复杂性,也影响了运行速度。可以改用字符串形式来表示布局,第1..3个数表示第一行的三个数,第4..6个数,表示第二行的三个数,第7..9个数表示第三行的三个数。这样,程序的判断和判重可以方便很多。
但如判重时使用的是一个存下所有情况的数组,那也能拿10分。
如:10分代码

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<string>using namespace std;int hash1=1,f[51000];string go,to,hashb[51000],ans[51000];int h=0,t=1;int a[4]={1,-1,0,0},    b[4]={0,0,1,-1};int out(int t){  int s=0;    do{s++;      t=f[t];    }while(f[t]!=0);        return s;}int pz(int n){    for(int i=1;i<=n;i++)       if(hashb[i]==ans[h]) return 0;      return 1;}int bfs(){      ans[1]=go;f[1]=0;    do{int i;        h++;        for( i=0;i<=8;i++)          if(ans[h][i]=='0') break;         for(int x=0;x<4;x++)         {                int nowx,nowy,tox,toy,wz;                nowx=i/3+1;                nowy=i%3+1;                tox=nowx+a[x];                toy=nowy+b[x];                wz=(tox-1)*3+toy-1;                if(tox>=1&&tox<=3&&toy>=1&&toy<=3&&wz>=0&&wz<=8&&nowx>=1&&nowx<=3&&nowy>=1&&nowy<=3)                {                    char c;                    c=ans[h][wz];                    ans[h][wz]=ans[h][i];                    ans[h][i]=c;                    if(pz(hash1)==1) {                        t++;ans[t]=ans[h];                        f[t]=h;                        hashb[++hash1]=ans[t];                        if(ans[t]==to) {return out(t);}                     }                      c=ans[h][i];                        ans[h][i]=ans[h][wz];                        ans[h][wz]=c;                }         }     }while(h<t);}int main(){    cin>>go;    hashb[1]=go;    to="123804765";    int answer;      answer=bfs();    printf("%d",answer);    return 0;}

现在我们发现判重的时候浪费了许多时间,所以我们可使用MAP或康托展开
100分(MAP)

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<string>#include<map>using namespace std;int hash1=1,f[510000];string go,to,ans[510000];int h=0,t=1;int a[4]={1,-1,0,0},    b[4]={0,0,1,-1};map<string,int>hashb;int out(int t){  int s=0;    do{s++;      t=f[t];    }while(f[t]!=0);        return s;}int bfs(){      ans[1]=go;f[1]=0;    do{int i;        h++;        for( i=0;i<=8;i++)          if(ans[h][i]=='0') break;         for(int x=0;x<4;x++)         {                int nowx,nowy,tox,toy,wz;                nowx=i/3+1;                nowy=i%3+1;                tox=nowx+a[x];                toy=nowy+b[x];                wz=(tox-1)*3+toy-1;                if(tox>=1&&tox<=3&&toy>=1&&toy<=3&&wz>=0&&wz<=8&&nowx>=1&&nowx<=3&&nowy>=1&&nowy<=3)                {                    char c;                    c=ans[h][wz];                    ans[h][wz]=ans[h][i];                    ans[h][i]=c;                    if(hashb[ans[h]]!=1) {                        t++;ans[t]=ans[h];                        f[t]=h;                        hashb[ans[h]]=1;                        if(ans[t]==to) {return out(t);}                     }                      c=ans[h][i];                        ans[h][i]=ans[h][wz];                        ans[h][wz]=c;                }         }     }while(h<t);}int main(){    cin>>go;    hashb[go]=1;    to="123804765";    int answer;      answer=bfs();    printf("%d",answer);    return 0;}