codevs1225 八数码难题

题目描述 Description

Yours和zero在研究A*启发式算法.拿到一道经典的A*问题,但是他们不会做,请你帮他们.
问题描述

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

输入描述 Input Description

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

输出描述 Output Description

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

样例输入 Sample Input

283104765

样例输出 Sample Output

4

数据范围及提示 Data Size & Hint

详见试题

思路:

(康托展开+双向广搜) or ida*

代码:

①双向广搜:

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<algorithm>
#define mx 4000000
using namespace std;

struct chess{
    int node[9];
    int step;
    int pos;
    bool cla;
};
int chart = 0,step[2][10000];
map<int,int> trans[2];
chess start,end;
bool jud[2][mx];
int m_jud[9][4] = {1,3,-1,-1,
                   0,4,2,-1,
                   1,5,-1,-1,
                   0,4,6,-1,
                   1,3,5,7,
                   2,4,8,-1,
                   3,7,-1,-1,
                   4,6,8,-1,
                   5,7,-1,-1};

int getval(chess x){
    int res = 1,val = 0;
    for(int i = 1;i <= 9;i++){
        val += res * x.node[i-1];
        res *= (i+1);
    }
    return val;
}
void putout(chess pt){
    cout<<"the class:"<<pt.cla<<endl;
    for(int i = 1;i <= 3;i++){
        for(int j = 1;j <= 3;j++){
            cout<<pt.node[(i-1) * 3 + j - 1] <<" ";
        }
        cout<<endl;
    }
    cout<<"steps: "<<pt.step<<" , pos: "<<pt.pos<<endl;
}
void init(){
    int co,md = 1;
    cin>>co;
    for(int i = 8;i >= 0;i--){
        start.node[i] = (co / md)% 10;
        md *= 10;
        if(start.node[i] == 0) start.pos = i;
        
    }
    start.cla = 0;
    end.node[0] = 1;
    end.node[1] = 2;
    end.node[2] = 3;
    end.node[3] = 8;
    end.node[4] = 0;
    end.node[5] = 4;
    end.node[6] = 7;
    end.node[7] = 6;
    end.node[8] = 5;
    end.step = start.step = 0;
    end.pos = 4;
    end.cla = 1;
}
void bfs(){
    queue<chess> now,then;
    now.push(start);
    now.push(end);
    chess test,h;
    int p,code;
    while(!now.empty()){
        h = now.front();
        p = h.pos;
        code = getval(h);
        trans[h.cla][code] = chart;
        step[h.cla][chart] = h.step;
        chart++;
        jud[h.cla][code] = 1;
        for(int i = 0,j = m_jud[p][i];j != -1 && i <= 3;i++,j = m_jud[p][i]){
            test = h;
            test.step++;
            swap(test.node[p],test.node[j]);
            code = getval(test);
            //if(jud[test.cla][code]) continue;
            test.pos = j;
            trans[test.cla][code] = chart;
            step[test.cla][chart] = test.step;
            chart++;
            if(jud[!test.cla][code]){
                cout<<step[0][trans[0][code]] + step[1][trans[1][code]]<<endl;
                return;
            }
            if(!jud[test.cla][code]){
                now.push(test);
                jud[test.cla][code] = 1;
            }
            
        }
        now.pop();
    }
}
int main(){

    init();    
    bfs();
    return 0;
}

②IDA*:

#include <iostream>
#include <cmath>
#include <cstdlib>
#include <cstdio>
#include <cstring>
using namespace std;
const unsigned int M = 1001;
int dir[4][2] = {
    1, 0, // Down
    -1, 0, // Up
    0,-1, // Left
    0, 1 // Right
};
typedef struct STATUS{
    int arr[3][3];
    int r,c;
}STATUS;
char dirCode[] = {"dulr"};
char rDirCode[] = {"udrl"};
char path[M]; // 最优解
STATUS begin, end = { 1,2,3,4,5,6,7,8,0,2,2 }; // 起始和终止状态
int maxDepth = 0; // 深度边界
int diff(const STATUS &cur) // 启发函数
{
    int i,j,k,m,ans=0;
    for(i=0;i<=2;i++)
        for(j=0;j<=2;j++)
        {
            if(cur.arr[i][j] != 0)
            {
                for(k=0;k<=2;k++)
                    for(m=0;m<=2;m++)
                    {
                        if(cur.arr[i][j] == end.arr[k][m])
                        {
                            ans+=abs(i-k)+abs(j-m);
                            break;
                        }
                    }
            }
        }
    return ans;
}
bool dfs(STATUS &cur, int depth, int h, char preDir)
{
    if(memcmp(&cur, &end, sizeof(STATUS)) == 0 )
    { // OK找到解了:)
        path[depth] = '/0';
        return true;
    }
    if( depth + h > maxDepth ) return false; // 剪枝
    STATUS nxt; // 下一状态
    for(int i=0; i<4; i++)
    {
        if(dirCode[i]==preDir) continue; // 回到上次状态,剪枝
        nxt = cur;
        nxt.r = cur.r + dir[i][0];
        nxt.c = cur.c + dir[i][1];
        if( !( nxt.r >= 0 && nxt.r < 3 && nxt.c >= 0 && nxt.c < 3 ) )
            continue;
        int nxth = h;
        int preLen,Len,desNum=cur.arr[nxt.r][nxt.c],desR=(desNum-1)/3,desC=(desNum-1)%3;
        preLen=abs(nxt.r-desR)+abs(nxt.c-desC);
        Len=abs(cur.r-desR)+abs(cur.c-desC);
        nxth = h - preLen + Len;
        swap(nxt.arr[cur.r][cur.c], nxt.arr[nxt.r][nxt.c]);
        path[depth] = dirCode[i];
        if(dfs(nxt, depth + 1, nxth, rDirCode[i]))
            return true;
    }
    return false;
}
int IDAstar()
{
    int nh = diff(begin);
    maxDepth = nh;
    while (!dfs(begin, 0, nh, '/0'))
        maxDepth++;
    return maxDepth;
}
void Input()
{
    char ch;
    int i, j;
    for(i=0; i < 3; i++){
        for(j=0; j < 3; j++){
            do{
                scanf("%c", &ch);
            }
            while( !( ( ch >= '1' && ch <= '8' ) || ( ch == 'x' ) ) ) 
                ;
            if( ch == 'x' ) {
                begin.arr[i][j] = 0;
                begin.r = i;
                begin.c = j;
            }
            else
                begin.arr[i][j] = ch - '0';
        }
    }
}
bool IsSolvable(const STATUS &cur)
{
    int i, j, k=0, s = 0;
    int a[8];
    for(i=0; i < 3; i++){
        for(j=0; j < 3; j++){
            if(cur.arr[i][j]==0) continue;
            a[k++] = cur.arr[i][j];
        }
    }
    for(i=0; i < 8; i++){
        for(j=i+1; j < 8; j++){
            if(a[j] < a[i])
                s++;
        }
    }
    return (s%2 == 0);
}
int main()
{
    Input();
    if(IsSolvable(begin)){
        IDAstar();
        printf("%s/n", path);
    }
    else
        printf("unsolvable/n");
    return 0;
}
原文地址:https://www.cnblogs.com/hyfer/p/5812534.html