poj1077

题意:给出一个八数码问题,求解法,不可解则输出unsolvable。

分析:可以用ida*算法,估价函数可以使用每个数码到其最终位置的最短距离之和。对于不可解的判断,我这里用迭代深度大于100时判定为不可解。

还有一种更高级的无解判断方法。就是将八数码矩阵中的空格忽略,然后将8个数字排成一排,第二行接在第一行后面,第三行接在第二行后面,通过观察我们发现移动空格不会影响这个8个数字组成的数列中逆序数队的奇偶性,因此如果逆序数对的奇偶性与目标状态不同则一定无解。至于为什么奇偶性相同就一定有解,我就不知道为什么了,不过这个命题确实是正确的。

可以将这种方法做适当修改并推广至15数码问题。

#include <iostream>

#include <stack>

#include <cmath>

using namespace std;



const    int        maxn = 10;



char    ans[100];

int        tot, dir[4][2] = {{-1,0},{0,1},{1,0},{0,-1}};



struct Node

{

    char    map[maxn];

    int        g, move, xpos;

}starts;



void init()

{

    for (int i = 0; i < 9; i++)

    {

        starts.map[i] = ' ';

        while (starts.map[i] == ' ')

            scanf("%c",&starts.map[i]);

        if (starts.map[i] == 'x')

        {

            starts.map[i] = 9;

            starts.xpos = i;

        } else

            starts.map[i] -= '0';

    }

}



int h(Node &a)

{

    int        x1, x2, y1, y2, i, r = 0;



    for (i = 0; i < 9; i++)

    {

        x1 = i / 3;

        y1 = i % 3;

        x2 = (a.map[i] - 1) / 3;

        y2 = (a.map[i] - 1) % 3;

        r += abs(x1 - x2) + abs(y1 - y2);

    }

    return r;

}



Node getchild(int a, Node &currents)

{

    int        x, y, pos, i;

    Node    r;

    

    x = currents.xpos / 3 + dir[a][0];

    y = currents.xpos % 3 + dir[a][1];

    r.xpos = -1;

    if (x < 0 || y < 0 || x > 2 || y > 2)

        return r;

    pos = x * 3 + y;

    r.xpos = pos;

    r.g = currents.g + 1;

    r.move = a;

    for (i = 0; i < 9; i++)

        r.map[i] = currents.map[i];

    r.map[pos] = 9;

    r.map[currents.xpos] = currents.map[pos];

    return r;

}



bool ida()

{

    int        pathlimit, i, temp, next;

    bool    success = 0;

    Node    currents, child;



    next = h(starts)/2;

    stack<Node> stk;

    do

    {

        pathlimit = next;

        if (pathlimit > 100)

            return false;

        tot = 0;

        starts.g = 0;

        starts.move = -1;

        next = 200;

        stk.push(starts);

        do

        {

            currents = stk.top();

            ans[currents.g] = currents.move;

            stk.pop();

            temp = h(currents);

            if (temp == 0)

            {

                tot = currents.g;

                success = true;

            }

            else if (pathlimit >= currents.g + temp / 2)

            {

                for (i = 0; i < 4; i++)

                {

                    child = getchild(i, currents);

                    if (child.xpos != -1 && abs(child.move - currents.move) != 2)

                        stk.push(child);

                }

            }else if (next > currents.g + temp / 2)

                next = currents.g + temp / 2;

        }while (!success && !stk.empty());

    }while (!success);

    return true;

}



void print()

{

    int        i;



    for (i = 1; i <= tot; i++)

        switch(ans[i])

        {

            case 0: printf("u"); break;

            case 1: printf("r"); break;

            case 2: printf("d"); break;

            case 3: printf("l"); break;

        }

    printf("\n");

}



int main()

{

    //freopen("t.txt", "r", stdin);

    init();

    if (ida())

        print();

    else

        printf("unsolvable\n");

    return 0;

}
View Code

 

你可能感兴趣的:(poj)