# BZOJ4899: 记忆的轮廓【概率期望DP】【决策单调性优化DP】

## Description

。初始昴位于1，当昴走到正确节点n时，便结束了路程。莎缇拉想知道，最优情况下，昴结束路程的期望步数是多

## Input

50<=p<=n<=700，m<=1500，T<=5。

## Output

T行每行一个实数表示每组数据的答案。请保留四位小数。

1
3 7 2
1 4
2 5
3 6
3 7

9.0000

## 思路

$dp_{j,x}+w_{j,i}\le dp_{k,x}+w_{k,i}(k<j)$

$dp_{j,x}+w_{j,i+1}\le dp_{k,x}+w_{k,i+1}(k<j)$

$w_{i,j}+w_{i+1,j+1}\le w_{i+1,j}+w_{i,j+1}$

#include <bits/stdc++.h>

using namespace std;

typedef long double ld;
const int N = 2010;

int n, m, p, d[N];
vector<int> g[N];
ld f[N], w[N][N], dp[N][N];

struct Node {
int pos, l, r;
Node() {}
Node(int pos, int l, int r): pos(pos), l(l), r(r) {}
} que[N];

void init() {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
w[i][j] = 0;
dp[i][j] = 1e9;
}
}
for (int i = 1; i <= m; i++) {
f[i] = 0;
d[i] = 0;
g[i].clear();
}
}

void dfs(int u) {
if (!(signed) g[u].size()) {
f[u] = 1;
return;
}
for (int i = 0; i < (signed) g[u].size(); i++) {
int v = g[u][i];
dfs(v);
f[u] += (f[v] + 1.0) / (1.0 * d[u]);
}
}

ld calc(int i, int j, int k) {
return dp[j][k - 1] + w[j][i];
}

int find(Node a, int b, int k) {
int l = a.l, r = n, res = n;
while (l <= r) {
int mid = (l + r) >> 1;
if (calc(mid, a.pos, k) >= calc(mid, b, k)) res = mid, r = mid - 1;
else l = mid + 1;
}
return res;
}

void solve() {
scanf("%d %d %d", &n, &m, &p); p--;
init();
for (int i = 1; i <= m - n; i++) {
int u, v; scanf("%d %d", &u, &v);
g[u].push_back(v);
++d[u];
}
for (int i = n; i >= 1; i--) dfs(i);
for (int i = 1; i <= n - 1; i++) ++d[i];
for (int i = n; i >= 1; i--) {
for (int j = i + 1; j <= n; j++) {
w[i][j] = w[i][j - 1] * d[j - 1] + f[j - 1] * (d[j - 1] - 1) + 1;
}
}
dp[1][1] = 0;
for (int i = 2; i <= p; i++) {
int ql = 1, qr = 1;
que[ql] = Node(i - 1, i - 1, n);
for (int j = i; j < n; j++) {
if (ql <= qr && ++que[ql].l > que[ql].r) ql++;
dp[j][i] = calc(j, que[ql].pos, i);
if (ql <= qr && calc(n, que[qr].pos, i) <= calc(n, j, i)) continue;
while (ql <= qr && calc(que[qr].l, que[qr].pos, i) >= calc(que[qr].l, j, i)) qr--;
if (ql > qr) {
que[++qr] = Node(j, j, n);
} else {
int cur = find(que[qr], j, i);
que[qr].r = cur - 1;
que[++qr] = Node(j, cur, n);
}
}
}
ld ans = 1e9;
for (int i = 1; i < n; i++) {
ans = min(ans, dp[i][p] + w[i][n]);
}
printf("%.4Lf\n", ans);
}

int main() {
#ifdef dream_maker
freopen("input.txt", "r", stdin);
#endif
int T; scanf("%d", &T);
while (T--) solve();
return 0;
}
posted @ 2018-12-09 18:19 Dream_maker_yk 阅读(...) 评论(...) 编辑 收藏