我是靠谱客的博主 彩色棒棒糖,最近开发中收集的这篇文章主要介绍[LOJ2542] 「PKUWC2018」随机游走(期望DP),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

题意

  • 给你一个 n n n个点的树,询问从 s s s号点出发,每次等概率选择一个相邻的点移动,求把集合 S S S每个点至少访问一次的期望步数。

首先我们很自然设 f [ u ] [ S ] f[u][S] f[u][S]为从 u u u号点出发访问 S S S集合至少一次的期望步数,那么我们可以写出DP方程:
f [ u ] [ S ] = 1 d e [ u ] ∑ e d g e ( u , v ) ( f [ v ] [ S ] + 1 ) ( u ∉ S ) f [ u ] [ S ] = 1 d e [ u ] ∑ e d g e ( u , v ) ( f [ v ] [ S − u ] + 1 ) ( u ∈ S ) f[u][S]=frac{1}{de[u]}sum_{edge(u,v)}(f[v][S]+1)(unotin S)\ f[u][S]=frac{1}{de[u]}sum_{edge(u,v)}(f[v][S-u]+1)(uin S) f[u][S]=de[u]1edge(u,v)(f[v][S]+1)(u/S)f[u][S]=de[u]1edge(u,v)(f[v][Su]+1)(uS)

我们发现每个集合 S S S要么从比它小的集合转移来,要么从它自己转移来,这个东西你从小到大枚举集合套高斯消元求解的话就是 O ( 2 n n 3 ) O(2^nn^3) O(2nn3)的,但这个复杂度显然不靠谱,考虑优化。方便起见,以下用 f [ u ] f[u] f[u]表示 f [ u ] [ S ] f[u][S] f[u][S]

考虑一类期望DP的套路,我们把 f [ u ] f[u] f[u]写成 A u × f [ f a [ u ] ] + B u A_utimes f[fa[u]]+B_u Au×f[fa[u]]+Bu的形式。先特判 u = S u=S u=S的情况,这个时候很显然 A u = B u = 0 A_u=B_u=0 Au=Bu=0,剩下的情况我们代回那个方程去解系数:
f [ u ] = f [ f a [ u ] ] d e [ u ] + ∑ u = f a [ v ] f [ v ] [ S ] d e [ u ] + 1 ( u ∉ S ) f [ u ] = f [ f a [ u ] ] d e [ u ] + ∑ u = f a [ v ] A v f [ u ] + B v d e [ u ] + 1 ( u ∉ S ) f [ u ] d e [ u ] = f [ f a [ u ] ] + ∑ u = f a [ v ] A v f [ u ] + B v + 1 ( u ∉ S ) f [ u ] = 1 d e [ u ] − ∑ A v × f [ f a [ u ] ] + ∑ B v + d e [ u ] d e [ u ] − ∑ A v ( u ∉ S ) f[u]=frac{f[fa[u]]}{de[u]}+sum_{u=fa[v]}frac{f[v][S]}{de[u]}+1(unotin S)\ f[u]=frac{f[fa[u]]}{de[u]}+sum_{u=fa[v]}frac{A_vf[u]+B_v}{de[u]}+1(unotin S)\ f[u]de[u]=f[fa[u]]+sum_{u=fa[v]}A_vf[u]+B_v+1(unotin S)\ f[u]=frac{1}{de[u]-sum A_v}times f[fa[u]]+frac{sum{B_v+de[u]}}{de[u]-sum A_v}(unotin S) f[u]=de[u]f[fa[u]]+u=fa[v]de[u]f[v][S]+1(u/S)f[u]=de[u]f[fa[u]]+u=fa[v]de[u]Avf[u]+Bv+1(u/S)f[u]de[u]=f[fa[u]]+u=fa[v]Avf[u]+Bv+1(u/S)f[u]=de[u]Av1×f[fa[u]]+de[u]AvBv+de[u](u/S)
u ∉ S unotin S u/S的情况更简单,因为它转移用到的信息都是算出来的,那么直接令:
A u = 0 , B u = 1 d e [ u ] ∑ e d g e ( u , v ) ( f [ v ] [ S − u ] + 1 ) A_u=0,B_u=frac{1}{de[u]}sum_{edge(u,v)}(f[v][S-u]+1) Au=0,Bu=de[u]1edge(u,v)(f[v][Su]+1)

我们最后往回代计算DP值就好了,复杂度 O ( n 2 n ) O(n2^n) O(n2n)

#include <bits/stdc++.h>

#define pb push_back
#define SZ(x) ((int)x.size())
#define For(i, a, b) for (int i = a; i <= b; ++ i)

using namespace std;

const int N = 18 + 3; 
const int M = 1 << 18;
const int mod = 998244353;

vector<int> G[N];

int f[N][M], A[N][M], B[N][M], de[N];

int qpow(int a, int x) {
	int ret = 1; 
	while (x) {
		if (x & 1) ret = 1ll * ret * a % mod;
		x >>= 1, a = 1ll * a * a % mod;
	}
	return ret;
}

void dfs(int u, int dad, int S) {
	for (auto v : G[u]) if (v ^ dad) dfs(v, u, S);
	if ((1 << (u - 1)) & S) {
		A[u][S] = 0;
		if (__builtin_popcount(S) == 1) 
			return (void)(B[u][S] = 0);
		for (auto v : G[u]) 
			(B[u][S] += f[v][S ^ (1 << (u - 1))] + 1) %= mod;
		B[u][S] = 1ll * B[u][S] * qpow(de[u], mod - 2) % mod;
	} else {
		A[u][S] = B[u][S] = de[u];
		for (auto v : G[u]) if (v ^ dad) {
			(A[u][S] += mod - A[v][S]) %= mod;
			(B[u][S] += B[v][S]) %= mod;
		}
		A[u][S] = qpow(A[u][S], mod - 2);
		B[u][S] = 1ll * B[u][S] * A[u][S] % mod;
	}
}

void DFS(int u, int dad, int S) {
	f[u][S] = (1ll * A[u][S] * f[dad][S] % mod + B[u][S]) % mod;
	for (auto v : G[u]) if (v ^ dad) DFS(v, u, S);
}

int main() {

	freopen("2542.in", "r", stdin);
	freopen("2542.out", "w", stdout);

	int x, y, z, n, q, s;

	scanf("%d%d%d", &n, &q, &s);
	For(i, 2, n) {
		scanf("%d%d", &x, &y);
		G[x].pb(y), G[y].pb(x);
	}

	int all = 1 << n;
	For(i, 1, n) 
		de[i] = SZ(G[i]);
	For(i, 1, all - 1) {
		dfs(1, 0, i);
		DFS(1, 0, i);
	}

	For(i, 1, q) {
		scanf("%d", &x), z = 0;
		For(j, 1, x) {
			scanf("%d", &y);
			z |= 1 << (y - 1);
		}
		printf("%dn", f[s][z]);
	}

	return 0;
}

最后

以上就是彩色棒棒糖为你收集整理的[LOJ2542] 「PKUWC2018」随机游走(期望DP)的全部内容,希望文章能够帮你解决[LOJ2542] 「PKUWC2018」随机游走(期望DP)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(59)

评论列表共有 0 条评论

立即
投稿
返回
顶部