UVa 12569:Planning mobile robot on Tree(EASY Version)(BFS)

5 篇文章 0 订阅

题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=842&page=show_problem&problem=4014

题意:有一颗n (4n15) 个结点的树,其中一个结点有一个机器人,还有一些结点有石头。每步可以把一个机器人或者石头移到一个相邻结点。任何情况下一个结点里不能有两个东西(石头或者机器人)。输入每个石头的位置和机器人的起点和终点,求最小步数的方案。如果有多解,可以输出任意解。如图所示,s=1,t=5时,最少需要16步:机器人1-6,石头2-1-7,机器人6-1-2-8,石头3-2-1-6,石头4-3-2-1,最后机器人8-2-3-4-5。(本段摘自《算法竞赛入门经典(第2版)》)

分析:
直接使用BFS搜索即可,用cantor展开来标记状态。

代码:

#include <iostream>
#include <algorithm>
#include <fstream>
#include <string>
#include <cstring>
#include <vector>
#include <queue>
#include <cmath>
#include <cctype>
#include <stack>
#include <set>

using namespace std;

const int maxn = 15 + 5, INF = 10;

struct Node
{
    int x, cantor, f, deep;
    int path[2];
    int a[maxn];
};

int T, x, y, n, m, s, t, ans, head, tail;
int a[maxn], tmp[maxn], v[600005];
vector< int > vec[maxn];
Node q[600005];

int Cantor(const int a[])
{
    int pos = -1, res = 0, fac = 1;
    for (int i = 1; i <= n; ++i)
    {
        if (a[i] == 1)
            res += fac;
        else if (a[i] == 2)
            pos = i;
        fac <<= 1;
    }
    res += ((1 << 15) * pos);
    return res;
}

void print(int head)
{
    if (q[head].f == -1)
        return;
    print(q[head].f);
    printf("%d %d\n", q[head].path[0], q[head].path[1]);
}

int BFS()
{
    memset(v, 0, sizeof(v));
    head = 0;
    tail = 0;
    q[tail].x = s;
    memcpy(q[tail].a, a, sizeof(a));
    q[tail].cantor = Cantor(q[tail].a);
    v[q[tail].cantor] = 1;
    q[tail].f = -1;
    q[tail++].deep = 0;
    while (head != tail)
    {
        if (q[head].x == t)
            return q[head].deep;
        for (int i = 1; i <= n; ++i)
            if (q[head].a[i])
            {
                for (int j = 0; j < vec[i].size(); ++j)
                {
                    int u = vec[i][j];
                    if (!q[head].a[u])
                    {
                        memcpy(tmp, q[head].a, sizeof(q[head].a));
                        swap(tmp[i], tmp[u]);
                        int c = Cantor(tmp);
                        if (!v[c])
                        {
                            int pos = (q[head].x == i) ? u : q[head].x;
                            q[tail].x = pos;
                            memcpy(q[tail].a, tmp, sizeof(tmp));
                            q[tail].cantor = c;
                            q[tail].f = head;
                            q[tail].path[0] = i;
                            q[tail].path[1] = u;
                            q[tail++].deep = q[head].deep + 1;
                            v[c] = 1;
                        }
                    }
                }
            }
        ++head;
    }
    return -1;
}

int main()
{
    scanf("%d", &T);
    for (int C = 0; C < T; ++C)
    {
        memset(a, 0, sizeof(a));
        scanf("%d%d%d%d", &n, &m, &s, &t);
        for (int i = 1; i <= n; ++i)
            vec[i].clear();
        a[s] = 2;
        for (int i = 0; i < m; ++i)
        {
            scanf("%d", &x);
            a[x] = 1;
        }
        for (int i = 0; i < n - 1; ++i)
        {
            scanf("%d%d", &x, &y);
            vec[x].push_back(y);
            vec[y].push_back(x);
        }
        ans = BFS();
        printf("Case %d: %d\n", C + 1, ans);
        if (ans != -1)
            print(head);
        printf("\n");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值