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);
}
View Code

 

posted @ 2019-02-11 20:39  探险家Mr.H  阅读(164)  评论(0编辑  收藏  举报