CTSC2011 幸福路径
给定⼀张有向图,每个点有个权值,蚂蚁从某个点开始,初始体⼒为1,每经过⼀条边,体⼒会变为原来的p(0<p<1)倍,每爬到⼀个点,获得的幸福度为该点的权值乘上体⼒。求蚂蚁幸福度的最⼤值,保留⼀位⼩数。
$n \leq 100,点权 \leq 100$
sol:
正解是自动机的泵引理,一看就不可做,考虑暴力碾标算
由于点权不超过 100,体力很小的时候点权的贡献也很小,保留一位小数就会把很小的贡献舍去
做一个 dp
设 $f_{(i,j,k)}$ 表示走了 $i$ 步,从 $j$ 走到 $k$ 的最大收益
那么 $f_{(2^i,j,k)} = max_{l}\{f_{(2^{i-1},j,l)} + f_{(2^{i-1},l,k)} \times p^{2^{i-1}}\}$
多做几遍就行了
#include <bits/stdc++.h> #define LL long long #define DB long double #define rep(i, s, t) for (register int i = (s), i##end = (t); i <= i##end; ++i) #define dwn(i, s, t) for (register int i = (s), i##end = (t); i >= i##end; --i) using namespace std; inline int read() { int x = 0, f = 1; char ch; for (ch = getchar(); !isdigit(ch); ch = getchar()) if (ch == '-') f = -f; for (; isdigit(ch); ch = getchar()) x = 10 * x + ch - '0'; return x * f; } const int maxn = 110; int n, m, st; DB ans, p, f[maxn][maxn], g[maxn][maxn], w[maxn]; int main() { cin >> n >> m; rep(i, 1, n) rep(j, 1, n) f[i][j] = i == j ? 0 : -1e30; rep(i, 1, n) { double x; cin >> x; w[i] = x; } cin >> st; double x; cin >> x; p = x; rep(i, 1, m) { int x = read(), y = read(); f[x][y] = p * w[y]; } for (; p > (DB)(1e-8); p *= p) { rep(i, 1, n) rep(j, 1, n) g[i][j] = -1e30; rep(i, 1, n) rep(j, 1, n) rep(k, 1, n) g[i][j] = max(g[i][j], f[i][k] + f[k][j] * p); memcpy(f, g, sizeof(f)); } rep(i, 1, n) ans = max(ans, f[st][i]); double res = ans + w[st]; printf("%.1f\n", res); }