UVA12569 树上的机器人规划(简单版) Planning mobile robot on Tree (EASY Version)

知识点:BFS,状态压缩

这个题首先一眼就是BFS,并且还要打印路径,然后就是最重要的问题,状态,首先直观的感觉,状态可以用三进制来表示,3的15次方一定能涵盖所有的情况,因为每个位置有三种可能,但是经过思考发现,只有一个机器人,那么我们把机器人提出来,用二进制来表示,某个位置是石头还是空格,然后再加一维,来表示机器人的位置,这样就行了,BFS的时候所有的石头都尝试移动,机器人也尝试移动,这样就能暴力的遍历所有的情况了,做到不漏,最后得到就是最少步数,输出的时候需要注意,起点不是到了机器人的起点,而是二进制数,以及机器人位置,共同组成的,二元组,到了这个的初始位置才是真的到了起点,倒序输出就行了

一开始不会三进制状态压缩,然后就想着用两个二进制数来表示状态,理论上应该是可行的,但是实际不行,空间啥的应该不行,这个题还真亏了读题,发现只有一个机器人,这个是做题的关键,但是一开始写的时候没有特判,输出-1,改了就过了,这个题写了1个小时,

#include <bits/stdc++.h>

using namespace std;

const int N = 16;
const int M = 500;

struct state {
	int u, v;
	state() {}
	state(int a, int b): u(a), v(b) {}
} pre[(1 << N) + 5][N];

int n, m, s, e, start, dist[(1 << N) + 5][N], Case;
int tot, head[N], ver[M], nxt[M];

void add(int x, int y) {
	ver[++tot] = y;
	nxt[tot] = head[x]; head[x] = tot;
}

void bfs() {
	for (int i = 0; i < (1 << (n + 1)); i++) {
		for (int j = 1; j <= n; j++) dist[i][j] = -1;
	}
	queue<state> q;
	q.push(state(start, s));
	dist[start][s] = 0;
	while (!q.empty()) {
		state now = q.front(); q.pop();
		if (now.v == e) {
			int ans = dist[now.u][now.v];
			vector<state> vec;
			while (true) {
				state cur = pre[now.u][now.v];
				if (cur.v != now.v) {
					vec.push_back(state(cur.v, now.v));
				} else {
					int to, from;
					for (int i = 1; i <= n; i++) {
						int x1 = (cur.u >> i) & 1;
						int x2 = (now.u >> i) & 1;
						if (x1 && !x2) to = i;
						if (!x1 && x2) from = i;
					}
					vec.push_back(state(to, from));
				}
				now = cur;
				if (now.u == start && now.v == s) break;
			}
			reverse(vec.begin(), vec.end());
			printf("Case %d: %d\n", ++Case, ans);
			for (int i = 0; i < (int) vec.size(); i++) {
				printf("%d %d\n", vec[i].u, vec[i].v);
			}
			printf("\n");
			return;
		}
		for (int i = 1; i <= n; i++) {
			if (!((now.u >> i) & 1) && now.v != i) continue;
			if (((now.u >> i) & 1)) {
				for (int j = head[i]; j; j = nxt[j]) {
					int y = ver[j];
					if (!((now.u >> y) & 1) && now.v != y) {
						int cur = now.u;
						cur &= (~(1 << i));
						cur |= (1 << y);
						if (dist[cur][now.v] == -1) {
							q.push(state(cur, now.v));
							pre[cur][now.v] = now;
							dist[cur][now.v] = dist[now.u][now.v] + 1;
						}
					}
				}
			} else {
				for (int j = head[i]; j; j = nxt[j]) {
					int y = ver[j];
					if (!((now.u >> y) & 1)) {
						if (dist[now.u][y] == -1) {
							q.push(state(now.u, y));
							pre[now.u][y] = now;
							dist[now.u][y] = dist[now.u][now.v] + 1;
						}
					}
				}
			}
		}
	}
	printf("Case %d: -1\n\n", ++Case);
}

int main() {
	int T;
	scanf("%d", &T);
	while (T--) {
		tot = 0;
		memset(head, 0, sizeof(head));
		scanf("%d%d%d%d", &n, &m, &s, &e);
		start = 0;
		for (int i = 1; i <= m; i++) {
			int x;
			scanf("%d", &x);
			start |= (1 << x);
		}
		for (int i = 1; i <= n - 1; i++) {
			int x, y;
			scanf("%d%d", &x, &y);
			add(x, y); add(y, x);
		}
		bfs();
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值