BZOJ 1916 [Usaco2010 Open]冲浪

BZOJ_1916

    对于这种题目,我向来是很头晕的,不过按dp的套路来的话还是可以解决的。

    不妨用dp[i][j]表示在第i个点时,已经失控了j次,至少能得到的开心值。我们不妨只讨论j<K的情况,这时一共有两种选择,要么被失控,要么能主动选择。如果能主动选择的话,肯定会选接下来至少能得到的开心值最大的决策,而被失控的话,就要考虑至少能得到的开心值最小的决策了。最后再综合二者取最小值就是当前状态下至少能得到的开心值,写成状态转移方程就是dp[i][j]=min{max{dp[k][j] + w[i][k]},min{dp[k][j+1] + w[i][k]}},其中w[i][k]表示i到k这条边的开心值。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define MAXD 50010
#define MAXM 150010
#define INF 0x3f3f3f3f3f3f3f3fll
typedef long long LL;
int N, M, K, first[MAXD], e, next[MAXM], v[MAXM];
LL w[MAXM], dp[MAXD][11];
void add(int x, int y, int z)
{
    v[e] = y, w[e] = z;
    next[e] = first[x], first[x] = e ++;
}
void init()
{
    memset(first, -1, sizeof(first[0]) * (N + 1)), e = 0;
    for(int i = 0; i < M; i ++)
    {
        int x, y, z;
        scanf("%d%d%d", &x, &y, &z);
        add(x, y, z);
    }
}
LL dfs(int i, int j)
{
    if(dp[i][j] != INF) return dp[i][j];
    LL ans = 0, min = INF;
    for(int t = first[i]; t != -1; t = next[t])
    {
        ans = std::max(ans, dfs(v[t], j)) + w[t];
        if(j < K) min = std::min(min, dfs(v[t], j + 1) + w[t]);
    }
    ans = std::min(ans, min);
    return dp[i][j] = ans;
}
void solve()
{
    memset(dp, 0x3f, sizeof(dp[0]) * (N + 1));
    memset(dp[N], 0, sizeof(dp[N]));
    printf("%lld\n", dfs(1, 0));
}
int main()
{
    while(scanf("%d%d%d", &N, &M, &K) == 3)
    {
        init();
        solve();
    }
    return 0;
}
原文地址:https://www.cnblogs.com/staginner/p/2727662.html