HDU 1043

46 篇文章 0 订阅
24 篇文章 0 订阅

    一道十分经典的搜索问题,也顺便考察了一下八数码有解无解判断的知识和哈希的方法,所以导致了有很多种解法。不过杭电数据比北大的强,所以花了我好大一番功夫。我在这里采用了A*+康托展开(哈希)的方法,效果还不错。

    A*算法主要是估值函数函数,我这里的启发式函数采用了当前状态的每个数字距目标状态每个数字的曼哈顿距离之和。

    至于用康托展开进行哈希,可以参考康托展开;判断是否有解的方法,可以参考逆序对

    最后说一下,一定要判断没有解的情况,否则就TLE。

代码(C++):

#include <iostream>
#include <cmath>
#include <queue>
#include <cstring>
#include <cstdio>

#define N 3
#define MAX 370000
using namespace std;

const int dir[4][2]={{0, 1}, {0, -1}, {-1, 0}, {1, 0}};
const char mov[4] = {'r', 'l', 'u', 'd'};
bool vis[MAX], number[N*N];
int num;

struct Puzzle{
    int p[N][N];
    int blank[2];
    int g;
    double f0;
    int way;
    int pre;

    Puzzle()
    {
        g = 0;
        way = pre = -1;
        f0 = 0.0;
    }
} puzzle[MAX];

struct cmp{
    bool operator() (int a, int b)
    {
        return puzzle[a].f0 > puzzle[b].f0;
    }
};

int heuristic(int puzzle[][N])
{
    int x, y, num, dist=0;
    for(int i=0; i<N; i++)
    {
        for(int j=0; j<N; j++)
        {
            num = puzzle[i][j];
            if(num!=0)
            {
                x = (num-1) / N;
                y = (num-1) % N;
            }else{
                x = N-1;
                y = N-1;
            }
            dist += abs(x-i) + abs(y-j);
        }
    }
    return dist;
}

Puzzle successor(int id, int x, int y, int i)
{
    Puzzle node = puzzle[id];

    node.p[node.blank[0]][node.blank[1]] = node.p[x][y];
    node.p[x][y] = 0;
    node.blank[0] = x;
    node.blank[1] = y;
    node.way = i;
    node.g += 1;
    node.f0 = node.g + heuristic(node.p);
    node.pre = id;

    return node;
}

bool is_goal(int puzzle[][N])
{
    int x, y, num;
    for(int i=0; i<N; i++)
    {
        for(int j=0; j<N; j++)
        {
            num = puzzle[i][j];
            if(0==num)
            {
                x = N-1;
                y = N-1;
            }else{
                x = (num-1) / N;
                y = (num-1) % N;
            }
            if(x!=i || y!=j) return false;
        }
    }
    return true;
}

int factorial(int n)
{
    if(1==n||0==n) return 1;
    else return n*factorial(n-1);
}

int hash_value(int puzzle[][N])
{
    int a, k, seq=0, c=N*N-1;

    memset(number, false, sizeof(number));
    for(int i=0; i<N; i++)
    {
        for(int j=0; j<N; j++)
        {
            a = 0;
            k=0;
            while(puzzle[i][j]>k)      //0~N*N-1
            {
               if(false == number[k]) a++;
               k++;
            }
            number[k]=true;
            seq += a * factorial(c);
            c--;
        }
    }
    return seq;
}

void set_visit(int puzzle[][N])
{
    int seq;
    seq = hash_value(puzzle);
    vis[seq] = true;
}

bool is_visit(int puzzle[][N])
{
    int seq;
    seq = hash_value(puzzle);
    return vis[seq];
}

void print_process(int id)
{
    if(-1==puzzle[id].pre) return;

    print_process(puzzle[id].pre);
    printf("%c", mov[puzzle[id].way]);
}

bool check(int puzzle[][N])     //此处只针对8数码
{
    int sum=0;

    for(int i=0; i<N*N; i++)
    {
        if(puzzle[i/N][i%N]==0) continue;
        for(int j=i+1; j<N*N; j++)
        {
            if(puzzle[j/N][j%N]==0) continue;
            if(puzzle[i/N][i%N]>puzzle[j/N][j%N]) sum++;
        }
    }
    if(sum%2==0) return true;
    else return false;
}

int main()
{
    //freopen("in.txt", "r", stdin);

    int nx, ny, id;
    bool find_flag;
    char ch;
    priority_queue<int, vector<int>, cmp> OPEN;
    Puzzle node, tmp;


    while(scanf("%c ", &ch)!=EOF)
    {
        num = 0;
        find_flag = false;
        memset(vis, false, sizeof(vis));   //用于判断是否访问过

        for(int i=0; i<N; i++)  //0代表空格
        {
            for(int j=0; j<N; j++)
            {
                if(i!=0||j!=0) scanf("%c ", &ch);
                if(ch == 'x')
                {
                    puzzle[num].p[i][j] = 0;
                    puzzle[num].blank[0] = i;
                    puzzle[num].blank[1] = j;
                }else puzzle[num].p[i][j] = ch-'0';
            }
        }


        if(!check(puzzle[num].p))
        {
            printf("unsolvable\n");
            continue;
        }else{
            puzzle[num].f0 = puzzle[num].g + heuristic(puzzle[num].p);
        }

        set_visit(puzzle[num].p);
        OPEN.push(num);
        num++;
        while(!OPEN.empty())
        {
            id = OPEN.top();
            node = puzzle[id];
            OPEN.pop();

            if(is_goal(node.p))
            {
                print_process(id);
                printf("\n");
                find_flag = true;
                break;
            }
            for(int i=0; i<4; i++)
            {
                nx = node.blank[0] + dir[i][0];
                ny = node.blank[1] + dir[i][1];
                if(nx>N-1||nx<0||ny>N-1||ny<0) continue;

                tmp = successor(id, nx, ny, i);
                if(!is_visit(tmp.p))
                {
                    set_visit(tmp.p);
                    puzzle[num] = tmp;
                    OPEN.push(num++);
                }
            }
        }
        while(!OPEN.empty()) OPEN.pop();
        if(!find_flag) printf("unsolvable\n");
    }
    return 0;
}

题目[http://acm.hdu.edu.cn/showproblem.php?pid=1043]

Eight

Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Special Judge

Problem Description

The 15-puzzle has been around for over 100 years; even if you don’t know it by that name, you’ve seen it. It is constructed with 15 sliding tiles, each with a number from 1 to 15 on it, and all packed into a 4 by 4 frame with one tile missing. Let’s call the missing tile ‘x’; the object of the puzzle is to arrange the tiles so that they are ordered as:

 1  2  3  4
 5  6  7  8
 9 10 11 12
13 14 15  x

where the only legal operation is to exchange ‘x’ with one of the tiles with which it shares an edge. As an example, the following sequence of moves solves a slightly scrambled puzzle:

 1  2  3  4     1  2  3  4     1  2  3  4     1  2  3  4
 5  6  7  8     5  6  7  8     5  6  7  8     5  6  7  8
 9  x 10 12     9 10  x 12     9 10 11 12     9 10 11 12
13 14 11 15    13 14 11 15    13 14  x 15    13 14 15  x
            r->            d->            r->

The letters in the previous row indicate which neighbor of the ‘x’ tile is swapped with the ‘x’ tile at each step; legal values are ‘r’,’l’,’u’ and ‘d’, for right, left, up, and down, respectively.

Not all puzzles can be solved; in 1870, a man named Sam Loyd was famous for distributing an unsolvable version of the puzzle, and
frustrating many people. In fact, all you have to do to make a regular puzzle into an unsolvable one is to swap two tiles (not counting the missing ‘x’ tile, of course).

In this problem, you will write a program for solving the less well-known 8-puzzle, composed of tiles on a three by three
arrangement.

Input

You will receive, several descriptions of configuration of the 8 puzzle. One description is just a list of the tiles in their initial positions, with the rows listed from top to bottom, and the tiles listed from left to right within a row, where the tiles are represented by numbers 1 to 8, plus ‘x’. For example, this puzzle

1 2 3 
x 4 6 
7 5 8 

is described by this list:

1 2 3 x 4 6 7 5 8

Output

You will print to standard output either the word “unsolvable”, if the puzzle has no solution, or a string consisting entirely of the letters ‘r’, ‘l’, ‘u’ and ‘d’ that describes a series of moves that produce a solution. The string should include no spaces and start at the beginning of the line. Do not print a blank line between cases.

Sample Input

2  3  4  1  5  x  7  6  8

Sample Output

ullddrurdllurdruldr
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值