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("
");
}

int main()
{
    //freopen("t.txt", "r", stdin);
    init();
    if (ida())
        print();
    else
        printf("unsolvable
");
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/rainydays/p/3201519.html