八数码难题

题目描述

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

输入输出格式

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

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

输入输出样例

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

本题正解应该是康托展开 + bfs 但是我弱啊,并不会康托展开,但是其实bfs + map判重也是可以过的,毕竟棋盘并不是很大,只是3 * 3大小而已,(我感觉IDA*也可以,但是我并没有打出来)。
这道题,我一开始是9位数字改成3 * 3 来存储,后来在用map判重的时候我发现还要转回来,所以我索性就直接在这个9位字符串上进行操作,对于上下左右进行转移,直接swap(),但是后面一定要再swap()回来,因为在开始调用一个新的队列队首时,此时用的都是当前从队列中取出来的那个九位字符串,如果不修改回来,循环下一次时,会发生转移的两点都不是0的情况,同时为了不让程序重复搜索或者陷入一个循环,需要用map<string,int>来判重,此时当你写完进行Ctrl c ,Ctrl v之后你会发现你满心欢喜的等待的AC并不会出现,却而代之的是WA ,这是为什么呢?
其实原因就是,当你进行转移操作时,3,-3只需判定在棋盘内即可并不会出现什么问题,但(从第零位开始)是1对于第三位,第六位,-1对于第二位,第五位,都是不可能成立的,因为此时他们位于最边缘当这样移动后是不成立的,需要进行特判,然后就可以愉快地AC了。

贴代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
#include<queue>
using namespace std;
string n;
int ans = 200000;
map<string,int>flag;
int move[5] = {0,3,-3,-1,1};//四个方向
int start;
string aim = "123804765";
int check(string a){//判断全局,是否到达目标状态
    for(int i = 0; i<=8; i++){
        if(a[i] != aim[i])return 0;
    }
    return 1;
}
queue<string>que;
queue<int>q;
int dx,begin;
int main(){
    cin >> n;
    que.push(n);
    q.push(0);
     while(!que.empty()){
    	string f = que.front();que.pop();
    	int v = q.front();q.pop();
    	if(flag[f] == 1)continue;
        if(check(f)){
    		ans = min(ans,v);
                continue;
        }
        flag[f] = 1;
    	for(int i = 0; i<=8; i++){
    		if(f[i] == '0'){
    			dx = i;
    			break;
            }
        }
        
        for(int i = 1; i<=4; i++){
      //特判特殊点
        if(dx == 3 && move[i] == -1)continue;
        if(dx == 6 && move[i] == -1)continue;
        if(dx == 2 && move[i] == 1)continue;
        if(dx == 5 && move[i] == 1)continue;
        //如果移动符合条件    
        if(dx + move[i] <= 8 && dx + move[i] >= 0){
               swap(f[dx+move[i]],f[dx]);
                if(flag[f] == 1){//此状态已经搜过
                swap(f[dx+move[i]],f[dx]);continue;	
                }
                que.push(f);
                q.push(v+1);
                swap(f[dx+move[i]],f[dx]);
            }
        }
    }
    cout <<ans;
    return 0;
}


posted @ 2018-11-08 14:50  Euplectella  阅读(195)  评论(0编辑  收藏  举报