BZOJ3052 [wc2013]糖果公园
BZOJ3757 苹果树

BZOJ1415 [Noi2005]聪聪和可可

laekov posted @ 2015年2月26日 20:19 in 未分类 with tags bzoj dp expection , 567 阅读

最近很颓啊。

 

这题很久之前看过。当时以为是高消就没管。然后开坑之神idy做了之后仔细一想才知道不是。

 

这题的做法是dp。首先因为边数少所以不用floyd,直接bfs预处理出所有t[i][j]表狼在i,兔子在j的时候狼下一步去哪。然后有一个结论是每一步两个玩意的距离至少缩短1,所以状态是不会有环的,这也是为啥可以不用高消。然后坑点是不能直接开状态队列,因为那不是拓补序。要先把每个点的入度算出来再跑dp。结局是我的代码超长。

 

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

struct edge {
	int t;
	edge *next;
};

#define mkword(_x_,_y_) (((_x_)<<16)|(_y_))
#define hiword(_x_) ((_x_)>>16)
#define loword(_x_) ((_x_)&0x0000ffff)

const int maxn = 1009;
const int maxst = 1000009;
const int inf = 0x3f3f3f3f;

int n, m, st, te, deg[maxn], d[maxn], t[maxn][maxn], ind[maxn][maxn];
edge elst[maxn << 1], *ep(elst), *head[maxn];
double f[maxn][maxn], g[maxn][maxn], c[maxn], ans;

inline void addEdge(int u, int v) {
	ep-> t = v;
	ep-> next = head[u];
	head[u] = ep ++;
}

void bfs(int p0) {
	static int q[maxn];
	int hd(0), tl(1);
	memset(d, -1, sizeof(d));
	d[q[0] = p0] = 0;
	while (hd < tl) {
		int p(q[hd ++]);
		for (edge* e = head[p]; e; e = e-> next)
			if (d[e-> t] == -1) {
				d[e-> t] = d[p] + 1;
				q[tl ++] = e-> t;
			}
	}
	for (int p = 1; p <= n; ++ p)
		if (p == p0) {
			t[p][p] = p;
		}
		else {
			t[p][p0] = inf;
			for (edge* e = head[p]; e; e = e-> next)
				if (d[p] == d[e-> t] + 1 && e-> t < t[p][p0])
					t[p][p0] = e-> t;
		}
}

void dp() {
	static int q[maxst];
	static bool iq[maxn][maxn];
	int hd(0), tl(1);
	memset(iq, 0, sizeof(iq));
	memset(f, 0, sizeof(f));
	memset(g, 0, sizeof(g));
	memset(ind, 0, sizeof(ind));
	ans = 0;
	q[0] = mkword(st, te);
	iq[st][te] = 1;
	while (hd < tl) {
		int i(hiword(q[hd])), j(loword(q[hd])), i0, j0;
		++ hd;
		if (t[t[i][j]][j] != j) {
			for (edge* e = head[j]; e; e = e-> next) {
				i0 = t[t[i][j]][j];
				j0 = e-> t;
				++ ind[i0][j0];
				int zn(mkword(i0, j0));
				if (!iq[i0][j0]) {
					q[tl ++] = zn;
					iq[i0][j0] = 1;
				}
			}
			i0 = t[t[i][j]][j];
			j0 = j;
			++ ind[i0][j0];
			int zn(mkword(i0, j0));
			if (!iq[i0][j0]) {
				q[tl ++] = zn;
				iq[i0][j0] = 1;
			}
		}
	}
	memset(f, 0, sizeof(f));
	memset(g, 0, sizeof(g));
	g[st][te] = 1;
	ans = 0;
	q[0] = mkword(st, te);
	hd = 0;
	tl = 1;
	while (hd < tl) {
		int i(hiword(q[hd])), j(loword(q[hd])), i0, j0;
		++ hd;
		if (i == j) {
			ans += f[i][j];
		}
		else if (t[t[i][j]][j] == j) {
			ans += f[i][j] + g[i][j];
		}
		else {
			for (edge* e = head[j]; e; e = e-> next) {
				i0 = t[t[i][j]][j];
				j0 = e-> t;
				g[i0][j0] += g[i][j] * c[j];
				f[i0][j0] += (f[i][j] + g[i][j]) * c[j];
				int zn(mkword(i0, j0));
				-- ind[i0][j0];
				if (!ind[i0][j0])
					q[tl ++] = zn;
			}
			i0 = t[t[i][j]][j];
			j0 = j;
			g[i0][j0] += g[i][j] * c[j];
			f[i0][j0] += (f[i][j] + g[i][j]) * c[j];
			int zn(mkword(i0, j0));
			-- ind[i0][j0];
			if (!ind[i0][j0])
				q[tl ++] = zn;
		}
	}
}

int main() {
#ifndef ONLINE_JUDGE
	freopen("in.txt", "r", stdin);
#endif

	scanf("%d%d%d%d", &n, &m, &st, &te);
	memset(d, 0x3f, sizeof(d));
	memset(deg, 0, sizeof(deg));
	for (int i = 0; i < m; ++ i) {
		int u, v;
		scanf("%d%d", &u, &v);
		addEdge(u, v);
		addEdge(v, u);
		++ deg[u];
		++ deg[v];
	}
	for (int i = 1; i <= n; ++ i) {
		bfs(i);
		c[i] = 1.0 / (deg[i] + 1);
	}
	dp();
	printf("%.3lf\n", ans);
}

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter