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
", ans);
    
    return 0;
}
原文地址:https://www.cnblogs.com/sugewud/p/9928134.html