FOJ-2180 骑士

http://acm.fzu.edu.cn/problem.php?pid=2180
Time Limit: 5000 mSec Memory Limit : 32768 KB

Problem Description

在一个5×5的棋盘上有12个白色的骑士和12个黑色的骑士,
且有一个空位。在任何时候一个骑士都能按照骑士的走法(它可以走到和它横坐标相差为1,纵坐标相差为2或者横坐标相差为2,纵坐标相差为1的格子)移动到空位上。

给定一个初始的棋盘,怎样才能经过移动变成如下目标棋盘:

为了体现出骑士精神,他们必须以最少的步数完成任务。

Input

第一行有一个正整数T(T<=10) 表示一共有T组数据
接下来有T个5*5的矩形。0表示白色骑士1表示黑色骑士,*表示空位。(每组数据间有空行)

Output

对每组数据都输出一行。如果能在15步以内(包括15)到达目标状态,则输出步数,否则输出“Bored!”没有引号。

Sample Input

2
10110
01*11
10111
01001
00000

01011
110*1
01110
01010
00100

Sample Output

7
Bored!

思路

双向BFS+状态压缩
PS:map使用自定义类型要重载‘<’运算符,否则无法正常进行查找等操作

代码

#include <cstdio>
#include <queue>
#include <map>
using namespace std;
int T, dir[8][2] = { 2, 1, 1, 2, -2, -1, -1, -2, 2, -1, -2, 1, 1, -2, -1, 2 };
struct Elem
{
    Elem(int g, int x, int y, int st) : G(g), sx(x), sy(y), step(st) { }
    bool operator== (const Elem& e) const { return this->G == e.G && this->sx == e.sx && this->sy == e.sy; }
    bool operator< (const Elem& e) const { return this->G == e.G ? this->sx == e.sx ? this->sy < e.sy : this->sx < e.sx : this->G < e.G; }
    int G, sx, sy, step;
};
Elem ed(549855, 2, 2, 0); // 0000010000110001111011111
int bfs(Elem st)
{
    queue<Elem> Qst, Qed;
    map<Elem, int> visST, visED; // [G] = step
    Qst.push(st);
    Qed.push(ed);
    visST[st] = 0;
    visED[ed] = 0;
    while (!Qst.empty() && !Qed.empty())
    {
        Elem nst = Qst.front();
        Qst.pop();
        if (nst.step >= 8)
            return -1;
        for (int k = 0; k < 8; k++)
        {
            int nx = nst.sx + dir[k][0], ny = nst.sy + dir[k][1];
            if (nx < 0 || nx >= 5 || ny < 0 || ny >= 5)
                continue;
            Elem next(nst.G, nx, ny, nst.step + 1);
            if (nst.G & (1 << (nx * 5 + ny)))
                next.G |= (1 << (nst.sx * 5 + nst.sy)), next.G ^= (1 << (nx * 5 + ny));
            if (visST.find(next) == visST.end())
            {
                if (visED.find(next) != visED.end())
                    return next.step + visED[next];
                Qst.push(next);
                visST[next] = next.step;
            }
        }
        Elem ned = Qed.front();
        Qed.pop();
        if (ned.step >= 8)
            return -1;
        for (int k = 0; k < 8; k++)
        {
            int nx = ned.sx + dir[k][0], ny = ned.sy + dir[k][1];
            if (nx < 0 || nx >= 5 || ny < 0 || ny >= 5)
                continue;
            Elem next(ned.G, nx, ny, ned.step + 1);
            if (ned.G & (1 << (nx * 5 + ny)))
                next.G |= (1 << (ned.sx * 5 + ned.sy)), next.G ^= (1 << (nx * 5 + ny));
            if (visED.find(next) == visED.end())
            {
                if (visST.find(next) != visST.end())
                    return next.step + visST[next];
                Qed.push(next);
                visED[next] = next.step;
            }
        }
    }
    return -1;
}
int main()
{
    scanf("%d", &T);
    while (T--)
    {
        Elem st(0, 0, 0, 0);
        for (int i = 0; i < 5; i++)
        {
            getchar();
            for (int j = 0; j < 5; j++)
            {
                char ch;
                scanf("%c", &ch);
                if (ch == '1')
                    st.G = st.G | (1 << (i * 5 + j));
                else if (ch == '*')
                    st.sx = i, st.sy = j;
            }
        }
        getchar();
        if (st == ed)
            printf("0\n");
        else
        {
            int ans = bfs(st);
            if (ans == -1 || ans > 15)
                printf("Bored!\n");
            else
                printf("%d\n", ans);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值