洛谷 P1379 八数码难题 Label:判重&&bfs

Posted Radiumlrb

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷 P1379 八数码难题 Label:判重&&bfs相关的知识,希望对你有一定的参考价值。

特别声明:紫书上抄来的代码,详见P198 

题目描述

在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。

输入输出格式

输入格式:

 

输入初试状态,一行九个数字,空格用0表示

 

输出格式:

 

只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)

 

输入输出样例

输入样例#1:
283104765
输出样例#1:
4

判重一 //set

代码

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<set>//测试 
 5 #include<algorithm>
 6 using namespace std;
 7 typedef int state[9];
 8 
 9 state st[1000005],goal={1,2,3,8,0,4,7,6,5};
10 int dis[1000005],dx[]={-1,1,0,0},dy[]={0,0,-1,1};
11 
12 set<int> vis;
13 void init_lookup_table(){vis.clear();}
14 int try_to_insert(int s){
15     int v=0;
16     for(int i=0;i<9;i++)v=v*10+st[s][i];
17     if(vis.count(v)) return 0;
18     vis.insert(v);
19     return 1;
20 }
21 
22 int bfs(){
23     init_lookup_table();
24     int front=1,rear=2;
25     while(front<rear){
26         state& s=st[front];
27         if(memcmp(goal,s,sizeof(s))==0)return front;
28         
29         int z;
30         for(z=0;z<9;z++) if(!s[z]) break;
31         int x=z/3,y=z%3;
32         for(int d=0;d<4;d++){
33             int newx=x+dx[d];
34             int newy=y+dy[d];
35             int newz=newx*3+newy;
36             if(newx>=0&&newx<3&&newy>=0&&newy<3){
37                 state& t=st[rear];
38                 memcpy(&t,&s,sizeof(s));//Copy
39                 t[newz]=s[z];
40                 t[z]=s[newz];
41                 dis[rear]=dis[front]+1;
42                 if(try_to_insert(rear)) rear++;
43             }
44         }
45         front++;
46     }
47     return 0;
48 }
49 
50 int main(){
51 //    freopen("01.in","r",stdin);
52     string s;cin>>s;
53     for(int i=0;i<=9;i++)st[1][i]=s[i]-0;
54     
55     int ans=bfs();
56     if(ans>0) printf("%d\n",dis[ans]);
57     else printf("-1\n");
58     return 0;
59 }

紫书上说stl很慢,但是......

技术分享

膜拜洛谷测评机

 

不过这是一个好方法吧.比如状态很多但很分散就可以类比set

判重二 //hash

代码 

#include<iostream>
#include<cstring>
#include<cstdio>
#include<set>//测试 
#include<algorithm>
using namespace std;
typedef int state[9];

state st[1000005],goal={1,2,3,8,0,4,7,6,5};
int dis[1000005],dx[]={-1,1,0,0},dy[]={0,0,-1,1};

const int hashsize=1000003;
int head[hashsize],next[hashsize];
void init_lookup_table(){memset(head,0,sizeof(head));}
int hash(state& s){
    int v=0;
    for(int i=0;i<9;i++) v=v*10+s[i];
    return v%1000003;
}
int try_to_insert(int s){
    int h=hash(st[s]);
    int u=head[h];
    while(u){
        if(memcmp(st[u],st[s],sizeof(st[s]))==0 )return 0;
        u=next[u];
    }
    next[s]=head[h];
    head[h]=s;
    return 1;
}

int bfs(){
    init_lookup_table();
    int front=1,rear=2;
    while(front<rear){
        state& s=st[front];
        if(memcmp(goal,s,sizeof(s))==0)return front;
        
        int z;
        for(z=0;z<9;z++) if(!s[z]) break;
        int x=z/3,y=z%3;
        for(int d=0;d<4;d++){
            int newx=x+dx[d];
            int newy=y+dy[d];
            int newz=newx*3+newy;
            if(newx>=0&&newx<3&&newy>=0&&newy<3){
                state& t=st[rear];
                memcpy(&t,&s,sizeof(s));//Copy
                t[newz]=s[z];
                t[z]=s[newz];
                dis[rear]=dis[front]+1;
                if(try_to_insert(rear)) rear++;
            }
        }
        front++;
    }
    return 0;
}

int main(){
//    freopen("01.in","r",stdin);
    string s;cin>>s;
    for(int i=0;i<=9;i++)st[1][i]=s[i]-0;
    
    int ans=bfs();
    if(ans>0) printf("%d\n",dis[ans]);
    else printf("-1\n");
    return 0;
}

震惊!!!

技术分享

 

 判重三 //编码(只适用于码数很小的情况下,比如30!就不行)

代码

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<set>//测试 
 5 #include<algorithm>
 6 using namespace std;
 7 typedef int state[9];
 8 
 9 state st[1000005],goal={1,2,3,8,0,4,7,6,5};
10 int dis[1000005],dx[]={-1,1,0,0},dy[]={0,0,-1,1};
11 
12 int vis[362880],fact[9];
13 void init_lookup_table(){
14     fact[0]=1;
15     for(int i=1;i<9;i++) fact[i]=fact[i-1]*i;
16 }
17 int try_to_insert(int s){
18     int code=0;//把st[s]映射到整数code
19     for(int i=0;i<9;i++){
20         int cnt=0;
21         for(int j=i+1;j<9;j++)if(st[s][j]<st[s][i]) cnt++;
22         code+=fact[8-i]*cnt;
23     }
24     if(vis[code])return 0;
25     return vis[code]=1;
26 }
27 
28 int bfs(){
29     init_lookup_table();
30     int front=1,rear=2;
31     while(front<rear){
32         state& s=st[front];
33         if(memcmp(goal,s,sizeof(s))==0)return front;
34         
35         int z;
36         for(z=0;z<9;z++) if(!s[z]) break;
37         int x=z/3,y=z%3;
38         for(int d=0;d<4;d++){
39             int newx=x+dx[d];
40             int newy=y+dy[d];
41             int newz=newx*3+newy;
42             if(newx>=0&&newx<3&&newy>=0&&newy<3){
43                 state& t=st[rear];
44                 memcpy(&t,&s,sizeof(s));//Copy
45                 t[newz]=s[z];
46                 t[z]=s[newz];
47                 dis[rear]=dis[front]+1;
48                 if(try_to_insert(rear)) rear++;
49             }
50         }
51         front++;
52     }
53     return 0;
54 }
55 
56 int main(){
57 //    freopen("01.in","r",stdin);
58     string s;cin>>s;
59     for(int i=0;i<=9;i++)st[1][i]=s[i]-0;
60     
61     int ans=bfs();
62     if(ans>0) printf("%d\n",dis[ans]);
63     else printf("-1\n");
64     return 0;
65 }

技术分享

总结起来就是:效率 hash>编码>set

另外这里有一个详细的转载:http://blog.csdn.net/ouxijv/article/details/7203027

 

以上是关于洛谷 P1379 八数码难题 Label:判重&&bfs的主要内容,如果未能解决你的问题,请参考以下文章

洛谷 P1379 八数码难题

洛谷P1379八数码难题

[LGOJ]P1379八数码难题[双向广搜].cpp

P1379 八数码难题

洛谷P1379 八数码难题

洛谷 P1379 八数码难题