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; }