UVa 10422 - Knights in FEN

本文介绍了一种解决UVa10422骑士问题的方法,通过使用哈希表记录状态,实现了一个高效的广度优先搜索算法。文章详细解释了如何利用BKDRHash函数生成哈希值,并通过链地址法处理哈希冲突。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门UVa 10422 - Knights in FEN


这题和八数码问题是一样的,但是我还是不会写。。。

参考了shuangde800的解题报告。

说是参考,其实就是看一句理解一句写一句。。。对哈希表和八数码有了一个初步的了解。

还有这篇文章各种常用字符串Hash函数比较,很厉害的样子。。

因为以前都是用结构体+指针方式写链表,突然看到数组表示的,很不习惯。

在这里理解了很久。

inline int TryToInsert(int s)
{
    int h = BKDRHash(que[s]);
    int u = head[h];
    while (u)
    {
        if (memcmp(que[u], que[s], sizeof(que[s])) == 0)
            return 0;
        u = next[u];
    }
    next[s] = head[h];  //把当前的哈希值的首部放到后面
    head[h] = s;    //放到对应的哈希值的首部
    return 1;
}


其实实际上就是这么一个图




如果没有冲突的哈希值,一切好说。

如果有冲突的,就顺着链表找下去,如果找不到,说明这个状态没有到达过,把它插入到哈希值的第一位,连接原本的第一位和现在的第一位。


#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN = 5000000;
const int HashSize = 3000000;

typedef char State[5][5];
State que[MAXN], start, goal = {{'1','1','1','1','1'},
                                {'0','1','1','1','1'},
                                {'0','0',' ','1','1'},
                                {'0','0','0','0','1'},
                                {'0','0','0','0','0'}};

int dir[][2] = {{-1, -2}, {-2, -1}, {-2, 1}, {-1, 2}, {1, 2}, {2, 1}, {2, -1}, {1, -2}};
int step[MAXN], ans;
int head[HashSize], next[MAXN];

inline int BKDRHash(State &s);
inline int TryToInsert(int s);
void BFS();

int main()
{
    //freopen("input.txt", "r", stdin);
    int i, j, T;
    scanf("%d%*c", &T);
    while (T--)
    {
        for (i = 0; i < 5; i++)
            gets(start[i]);
        BFS();
        if (ans != -1)
            printf("Solvable in %d move(s).\n", ans);
        else
            printf("Unsolvable in less than 11 move(s).\n");
    }
    return 0;
}

inline int BKDRHash(State &s)
{
    unsigned int seed = 131;
    unsigned int hashValue = 0;
    for (int i = 0; i < 5; i++)
        for (int j = 0; j < 5; j++)
            hashValue = hashValue * seed + s[i][j];
    return (hashValue & 0x7FFFFFF) % HashSize;
}

inline int TryToInsert(int s)
{
    int h = BKDRHash(que[s]);
    int u = head[h];
    while (u)
    {
        if (memcmp(que[u], que[s], sizeof(que[s])) == 0)
            return 0;
        u = next[u];
    }
    next[s] = head[h];  //把当前的哈希值的首部放到后面
    head[h] = s;    //放到对应的哈希值的首部
    return 1;
}

void BFS()
{
    memset(head, 0, sizeof(head)); //Initial the hash table
    int front = 0, rear = 1;
    memcpy(que[0], start, sizeof(start));
    step[0] = 0;
    while (front < rear)
    {
        State &s = que[front];
        if (step[front] > 10)
        {
            ans = -1;
            return;
        }
        if (memcmp(goal, s, sizeof(s)) == 0)
        {
            ans = step[front];
            return;
        }
        int x, y;
        bool flag = false;
        for (int i = 0; i < 5; i++)
            for (int j = 0; j < 5; j++)
            {
                if (flag)
                    break;
                if (s[i][j] == ' ')
                {
                    x = i, y = j;
                    flag = true;
                    break;
                }
            }
        for (int i = 0; i < 8; i++)
        {
            int dx = x + dir[i][0];
            int dy = y + dir[i][1];
            if (dx >= 0 && dx < 5 && dy >= 0 && dy < 5)
            {
                State &t = que[rear];
                memcpy(t, s, sizeof(s));
                t[dx][dy] = s[x][y];
                t[x][y] = s[dx][dy];    //移动空格
                step[rear] = step[front] + 1;
                if (TryToInsert(rear))  //如果不存在重复的,就放到队列里。
                    rear++;
            }
        }
        front++;
    }
    ans = -1;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值