P1379 八数码难题

八数码难题

题目描述

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

输入格式

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

输出格式

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

样例 #1

样例输入 #1

283104765

样例输出 #1

4

提示

样例解释

图中标有 0 0 0 的是空格。绿色格子是空格所在位置,橙色格子是下一步可以移动到空格的位置。如图所示,用四步可以达到目标状态。

并且可以证明,不存在更优的策略。

code:

#include<iostream>
#include<queue>
#include<cstring>
#include<unordered_map>
#include<string>
using namespace std;
string s;
unordered_map<string ,int >dist;//dist记录走到string这个状态需要多少步
//map["123804765"]=n;
queue<string>q;
int dx[]={-1,0,1,0};
int dy[]={0,1,0,-1};
int bfs(string s){
    string end1="123804765";
    dist[s]=0;
    q.push(s);
    while(q.size()){
        auto t=q.front();
        q.pop();
        if(t==end1){
            return dist[t];
        }
        int distance=dist[t];
        int a=t.find('0');
        int x12=a/3;
        int y12=a%3;//找到0在的第几行第几列
        for(int i=0;i<4;i++){
            int x2=x12+dx[i];
            int y2=y12+dy[i];
            if(x2<0||x2>=3||y2<0||y2>=3) continue;
            int tmp=x2*3+y2;//将3*3矩阵坐标换成一维字符串的坐标
            swap(t[a],t[tmp]);
            if(!dist.count(t)){
                dist[t]=distance+1;
                q.push(t);
            }
            swap(t[a],t[tmp]);//恢复现场
        }
    }
    return -1;
}
int main(){
    cin>>s;
    int res=bfs(s);
    cout<<res<<endl;
    return 0;
}

优化的code:

#include<iostream>
#include<queue>
#include<cstring>
#include<unordered_map>
#include<string>
using namespace std;
const int N=10;
string s;
queue<string>q;
unordered_map<string ,int >dist;
unordered_map<string ,int >vis;
string end1="123804765";
int dx[]={-1,0,1,0};
int dy[]={0,1,0,-1};
int bfs(string s){
    dist[s]=0;
    dist[end1]=0;
    q.push(s),q.push(end1);
    vis[s]=1,vis[end1]=2;
    while(!q.empty()){
        auto t=q.front();
        q.pop();
        int distance=dist[t];
        int flag=vis[t];
        int x=t.find('0');
        int x0=x/3,y0=x%3;
        for(int i=0;i<4;i++){
            int a=x0+dx[i];
            int b=y0+dy[i];
            if(a<0||a>=3||b<0||b>=3) continue;
            swap(t[x],t[a*3+b]);//a*3+b二位转化成一维
            if(vis[t]+flag==3){
                int res1=dist[t];
                swap(t[x],t[a*3+b]);
                int res2=dist[t];
                return res1+res2+1;
            }
            if(!dist.count(t)){
                dist[t]=distance+1;
                q.push(t);
                vis[t]=flag;
            }
            swap(t[x],t[a*3+b]);
        }
    }
    return -1;
}
int main(){
    cin>>s;
    if(s==end1){
        cout<<0;
        return 0;//输入和输出一样的话就输出零
    }
    int res=bfs(s);
    cout<<res;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值