NOIP 2016 换教室(期望dp)
第一次做期望dp
并不知道每个阶段的期望之和就是整个的期望之和
所以一直卡在这
期望=代价*概率
然后注意只有申请了才算期望,否则按原来的。
这道题和前几个课程,申请的限制,当前选或不选,有关
这样很容易写出dp的状态
其实你如果打80分的暴力,会发现把那个暴力记忆化一下
就变成dp,就可以拿满分了,
做题的时候一定要搞清楚每个变量的意义是啥
自己没搞清楚导致数组开小WA两个点
在我的代码中,我在很努力的简化代码了(define)
#include<bits/stdc++.h> #define down(a, b) a = min(a, b) #define d(u, v) a[c[i-1][u]][c[i][v]] #define val(u, v) d(u, v) * (!u ? (1 - k[i-1]) : k[i-1]) * (!v ? (1 - k[i]) : k[i]) #define REP(i, a, b) for(register int i = (a); i < (b); i++) #define _for(i, a, b) for(register int i = (a); i <= (b); i++) using namespace std; const int MAXN = 2e3 + 10; const int MAXM = 300 + 10; double k[MAXN], dp[MAXN][MAXN][2]; int a[MAXM][MAXM], n, m, v, e; int c[MAXN][2]; int main() { scanf("%d%d%d%d", &n, &m, &v, &e); _for(i, 1, n) scanf("%d", &c[i][0]); _for(i, 1, n) scanf("%d", &c[i][1]); _for(i, 1, n) scanf("%lf", &k[i]); memset(a, 0x3f, sizeof(a)); _for(i, 0, v) a[i][i] = 0; _for(i, 1, e) { int u, v, w; scanf("%d%d%d", &u, &v, &w); a[u][v] = a[v][u] = min(a[u][v], w); } _for(K, 1, v) _for(i, 1, v) _for(j, 1, v) a[i][j] = min(a[i][j], a[i][K] + a[K][j]); memset(dp, 0x43, sizeof(dp)); dp[1][0][0] = dp[1][1][1] = 0; _for(i, 2, n) _for(j, 0, m) { down(dp[i][j][0], dp[i-1][j][0] + d(0, 0)); down(dp[i][j][0], dp[i-1][j][1] + d(1, 0) * k[i-1] + d(0, 0) * (1 - k[i-1])); if(j) down(dp[i][j][1], dp[i-1][j-1][0] + d(0, 1) * k[i] + d(0, 0) * (1 - k[i])); if(j) down(dp[i][j][1], dp[i-1][j-1][1] + val(0, 1) + val(0, 0) + val(1, 0) + val(1, 1)); } double ans = 1e17; _for(i, 0, m) down(ans, min(dp[n][i][0], dp[n][i][1])); printf("%.2lf\n", ans); return 0; }