UVA Planning mobile robot on Tree树上的机器人(状态压缩+bfs)

用(x,s)表示一个状态,x表示机器人的位置,s表示其他位置有没有物体。用个fa数组和act数组记录和打印路径,转移的时候判断一下是不是机器人在动。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 16;
const int maxe = 32;
const int MAXSTA = 491520+10; // 2^15*15
int head[maxn],to[maxe],nxt[maxe];
int ecnt;

void addEdge(int u,int v)
{
    to[ecnt] = v;
    nxt[ecnt] = head[u];
    head[u] = ecnt++;
}

struct Node
{
    int x,s;
    Node(){}
    Node(int X ,int S ){
        x = X; s = S;
    }
}q[MAXSTA];
int fa[MAXSTA],dist[MAXSTA];
struct Act
{
    int u,v;
    Act(int U = 0,int V = 0):u(U),v(V){}
}act[MAXSTA];
bool vis[32768][15];

int n,m,s,t,sta;

void print_ans(int u)
{
    if(~fa[u])print_ans(fa[u]);
    else return;
    printf("%d %d\n",act[u].u+1,act[u].v+1);
}

void bfs()
{
    int _front = 0,rear = 0;
    q[rear].x = s; q[rear].s = sta;
    fa[rear] = -1; dist[rear++] = 0;
    memset(vis,0,sizeof(vis));
    vis[sta][s] = true;
    while(_front<rear){
        Node &u = q[_front];
        if(u.x == t) {
            printf("%d\n",dist[_front]);
            print_ans(_front);
            return ;
        }
        for(int who = 0; who < n; who++) if(u.s>>who&1){
            int newSta = u.s^(1<<who);
            for(int i = head[who]; ~i; i = nxt[i]) if((u.s>>to[i]&1)^1) {
                Node &v = q[rear];
                v.s = newSta|1<<to[i];
                v.x = who != u.x ? u.x : to[i];
                if(!vis[v.s][v.x]){
                    vis[v.s][v.x] = true;
                    fa[rear] = _front;
                    act[rear].u = who;act[rear].v = to[i];
                    dist[rear++] = dist[_front] + 1;
                }
            }

        }
        _front++;
    }
    printf("-1\n");
}

int main()
{
    //freopen("in.txt","r",stdin);
    int T; scanf("%d",&T);
    for(int cas = 1; cas <= T; cas++){
        scanf("%d%d%d%d",&n,&m,&s,&t);
        s--; t--;
        sta = 1<<s;
        for(int i = 0; i < m; i++) {
            int t;
            scanf("%d",&t);
            sta |= 1<<(t-1);
        }
        ecnt = 0; memset(head,-1,sizeof(head));
        for(int i = 1; i < n; i++){
            int u,v; scanf("%d%d",&u,&v);
            u--;v--;
            addEdge(u,v); addEdge(v,u);
        }
        printf("Case %d: ",cas);
        bfs();
    }
    return 0;
}
时间: 2024-10-11 11:36:19

UVA Planning mobile robot on Tree树上的机器人(状态压缩+bfs)的相关文章

Uva 12569 Planning mobile robot on Tree (EASY Version)

基本思路就是Bfs: 本题的一个关键就是如何判段状态重复. 1.如果将状态用一个int型数组表示,即假设为int state[17],state[0]代表机器人的位置,从1到M从小到大表示障碍物的位置.那么如果直接用STL中的set是会超时的,但如果自己建立一个hash方法,像这样: int getKey(State& s) { long long v = 0; for(int i=0; i<=M; ++i ) { v = v * 10 + s[i]; } return v % hashSi

UVA-12569 Planning mobile robot on Tree (EASY Version) (BFS+状态压缩)

题目大意:一张无向连通图,有一个机器人,若干个石头,每次移动只能移向相连的节点,并且一个节点上只能有一样且一个东西(机器人或石头),找出一种使机器人从指定位置到另一个指定位置的最小步数方案,输出移动步骤. 题目分析:以机器人的所在位置和石头所在位置集合标记状态,状态数最多有15*2^15个.广搜之. 代码如下: # include<iostream> # include<cstdio> # include<string> # include<queue> #

UVA12569-Planning mobile robot on Tree (EASY Version)(BFS+状态压缩)

Problem UVA12569-Planning mobile robot on Tree (EASY Version) Accept:138  Submit:686 Time Limit: 3000 mSec  Problem Description  Input The first line contains the number of test cases T (T ≤ 340). Each test case begins with four integers n, m, s, t (

UVa 1252 - Twenty Questions(记忆化搜索,状态压缩dp)

题目链接:uva 1252 题意: 有n个长度为m的二进制串,每个都是不同的. 为了把所有字符串区分开,你可以询问,每次可以问某位上是0还是1. 问最少提问次数,可以把所有字符串区分开来. 思路来源于:点击打开链接 思路: m很小,可以考虑状态压缩. dp[s1][s2]表示询问的状态为s1时,此时能猜到状态包含s2时最小需要的步数. 当询问的几位=s2的二进制串小于2时就能区分出来了,dp[s1][s2]=0: 不能区分则再询问一次,s1|=(1<<k),如果问某位为0,则s2不变,问某位为

hdu4670(树上点分治+状态压缩)

树上路径的f(u,v)=路径上所有点的乘积. 树上每个点的权值都是由给定的k个素数组合而成的,如果f(u,v)是立方数,那么就说明f(u,v)是可行的方案. 问有多少种可行的方案. f(u,v)可是用状态压缩来表示,因为最多只有30个素数, 第i位表示第i个素数的幂,那么每一位的状态只有0,1,2因为3和0是等价的,所以用3进制状态来表示就行了. 其他代码就是裸的树分. 另外要注意的是,因为counts函数没有统计只有一个点的情况,所以需要另外统计. 1 #pragma warning(disa

Codeforces Round #316 (Div. 2) D. Tree Requests(DFS+状态压缩)

题意:给定一棵树,n个节点.每一个节点处有一个字母,结点的深度定义为节点到根结点1的距离, 有m个询问(u.v),每次回答以结点u为根的子树的深度为v的那些节点处的字母是否能组成一个回文串,特别的,空串也是回文串. 思路:首先说明推断回文串的方法,仅仅要出现次数为奇数个字母个数不超过2.那么这些字母一定能够组成回文串. 接下来考虑将树转成线性结构. 利用dfs+时间戳将结点依照深度存入一个线性结构里,Depth[i]数组里存的是深度为i的全部结点, 那么对于询问有三种情况.一种是dep[u]>=

UVA 10228 - Star not a Tree?(模拟退火)

UVA 10228 - Star not a Tree? 题目链接 题意:给定一些点,费马点(到这些点距离和最短),输出距离和 思路:模拟退火去搞,初始温度1W步,降温系数设为0.83,然后每次找周围4个方向,做10次保证答案准确 代码: #include <cstdio> #include <cstring> #include <cmath> #include <ctime> #include <cstdlib> #include <al

[hdu5593 ZYB&#39;s Tree] 树上统计

题意:给1棵N(≤500,000)个节点的树,每条边边权为1,求距离每个点距离不超过K(K≤10)的点的个数的xor和. 思路:由于K很小,可以考虑把距离作为状态的一部分,然后研究父子之间状态的联系.令ans[i][j]表示与i的距离为j的点的个数,那么ans[i][j]由两部分构成,一部分来源于子树,一部分来源于父亲,那么令f[i][j]表示从子树来的答案,g[i][j]表示从父亲来的答案,son(i)表示i的儿子,fa(i)表示i的父亲,则有: ans[i][j] = f[i][j] + g

uva 10304 Optimal Binary Search Tree (区间DP)

uva 10304 Optimal Binary Search Tree 题目大意:给出N个结点(已知每个结点的权值)来建树,建树时要满足以下规则:左子树的节点的值要全小于父节点,右子树的节点的值要全大于父节点.要求最后建出的树总权值最小.总权值=各结点乘以层数(从0层开始)之后相加的和. 解题思路:dp[i][j]代表区间第i个结点到第j个结点组成的树最小的总权值.dp[j][i]=min(dp[j][i],dp[j][k?1]+dp[k+1][i]+sum[i]?sum[j?1]?num[k