【题解】NOIP2016换教室

哇好开心啊!写的时候真的全然对于这个加法没有把握,但还是大着胆子试着写了一下——竟然过了样例?于是又调了一下就过啦。

不过想想也觉得是正确的吧,互相独立的事件对于期望的影响自然也是相互独立的,可以把所有的情况看成一个整体,不同的统计方式只是分组的区别,最后算出来的答案肯定是一样的。dp的状态比较显然:dp[i][j][0/1]代表当前在第i节课,已经用去了j次申请的机会,0/1分别代表当前这一节课是否申请。那么这个时候就分情况讨论,计算这一次的选择对于答案的影响。

这些不同的情况分别是:当前和上一次是否选择申请换课,申请换课的是否成功。

期望的计算式:成功的概率*成功的代价+失败的概率*失败的代价。

#include <bits/stdc++.h>
using namespace std;
#define maxn 2050
#define INF 1047483640
#define maxm 2050
#define maxv 400
int n, m, v, e, dis[maxv][maxv], c[maxn], d[maxn];
double ans = 9999999, dp[maxn][maxm][2], k[maxn];

int read()
{
    int x = 0, k = 1;
    char c;
    c = getchar();
    while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * k;
}

void init()
{
    for(int i = 1; i <= v; i ++)
        for(int j = i + 1; j <= v; j ++)
            dis[i][j] = dis[j][i] = INF;
    
    for(int i = 1; i <= n; i ++)
        for(int j = 0; j <= m; j ++)
            dp[i][j][0] = dp[i][j][1] = INF;
}

double gmin(double &x, double y)
{
    x = (x < y) ? x : y;
}

int gmin2(int &x, int y)
{
    x = (x < y) ? x : y;
}

void Floyd()
{
    for(int k = 1; k <= v; k ++)
        for(int i = 1; i <= v; i ++)
            for(int j = 1; j <= v; j ++)
                gmin2(dis[i][j], dis[i][k] + dis[k][j]); 
}

int main()
{
    n = read(), m = read(), v= read(), e = read();
    for(int i = 1; i <= n; i ++) c[i] = read();
    for(int i = 1; i <= n; i ++) d[i] = read();
    init(); 
    dp[0][0][0] = dp[0][0][1] = 0;
    for(int i = 1; i <= n; i ++) scanf("%lf", &k[i]);
    for(int i = 1; i <= e; i ++)
    {
        int x = read(), y = read(), z = read();
        dis[x][y] = dis[y][x] = min(dis[y][x], z);
    }
    for(int i = 1; i <= v; i ++) dis[i][i] = 0;
    Floyd();
    for(int i = 1; i <= v; i ++)
        dis[i][0] = dis[0][i] = 0;
    c[0] = d[0] = 0, k[0] = 1;
    for(int i = 1; i <= n; i ++)
        for(int j = 0; j <= m; j ++)
        {
            gmin(dp[i][j][0], dp[i - 1][j][0] + dis[c[i]][c[i - 1]]);
            gmin(dp[i][j][0], dp[i - 1][j][1] + dis[c[i]][c[i - 1]] * (1 - k[i - 1]) + dis[c[i]][d[i - 1]] * k[i - 1]);
            if(j) gmin(dp[i][j][1], dp[i - 1][j - 1][0] + dis[c[i]][c[i - 1]] * (1 - k[i]) + dis[d[i]][c[i - 1]] * k[i]);
            double tem = 0;
            tem += dis[c[i]][c[i - 1]] * (1 - k[i]) * (1 - k[i - 1]);
            tem += dis[c[i]][d[i - 1]] * (1 - k[i]) * k[i - 1];
            tem += dis[d[i]][c[i - 1]] * k[i] * (1 - k[i - 1]);
            tem += dis[d[i]][d[i - 1]] * k[i] * k[i - 1];
            if(j) gmin(dp[i][j][1], dp[i - 1][j - 1][1] + tem);
        }
    for(int i = 0; i <= m; i ++)
        gmin(ans, min(dp[n][i][0], dp[n][i][1]));
    printf("%.2lf", ans);
    return 0;
}
原文地址:https://www.cnblogs.com/twilight-sx/p/8456805.html