• 【NOIP2016】换教室 题解(期望DP)


    前言:状态贼鸡儿多,眼睛快瞎了。

    -----------------------

    题目链接

    题目大意:给定$n(课程数),m(可换次数),v(教室数),e(无向边数)$,同时给定原定教室$c[i]$和可换教室$d[i]$,换教室成功概率为$k[i]$,边权为$w[i]$。问耗费体力的最小期望值。

    -----------------

    设$f[i][j][0/1]$表示上完$i$节课,换教室$j$次后($0$表示此刻不换,$1$表示刺客换)的最小期望值。

    $C1=c[i-1],C2=c[i],C3=d[i-1],C4=d[i],mp[i][j]表示i到j的距离。$

    先考虑不换的情况:

    f[i][j][0]=min(f[i][j][0],min(f[i-1][j][0]+dis[c[i-1]][c[i]],f[i-1][j][1]+(1-k[i-1])*dis[c[i-1]][c[i]]+k[i-1]*dis[d[i-1]][c[i]]))

     

    考虑换的情况:

    f[i][j][1]=min(f[i][j][1],min(f[i-1][j-1][0]+dis[c[i-1]][c[i]]*(1-k[i])+dis[c[i-1]][d[i]]*k[i],f[i-1][j-1][1]+dis[d[i-1]][d[i]]*k[i-1]*k[i]+dis[d[i-1]][c[i]]*k[i-1]*(1-k[i])+dis[c[i-1]][c[i]]*(1-k[i-1])*(1-k[i])+dis[c[i-1]][d[i]]*(1-k[i-1])*k[i]))

     

    预处理最短路可以用$Floyd$,$ans=min(ans,min(f[n][i][0],f[n][i][1]))$。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int MAXN = 2e3 + 5;
    const double inf = 1e17 + 5;
    int n, m, v, e, c[MAXN][2], mp[305][305];
    double k[MAXN], dp[MAXN][MAXN][2], ans;
    inline int read() {
        char ch = getchar(); int u = 0, f = 1;
        while (!isdigit(ch)) {if (ch == '-')f = -1; ch = getchar();}
        while (isdigit(ch)) {u = u * 10 + ch - 48; ch = getchar();}return u * f;
    }
    int main(){
        memset(mp, 63, sizeof(mp));
        n = read(); m = read(); v = read(); e = read();
        for (register int i = 1; i <= n; i++)c[i][0] = read();
        for (register int i = 1; i <= n; i++)c[i][1] = read();
        for (register int i = 1; i <= n; i++)scanf("%lf", &k[i]);
        for (register int i = 1; i <= e; i++){
            int x = read(), y = read(), w = read();
            mp[x][y] = mp[y][x] = min(mp[x][y], w);
        }
        for (register int k = 1; k <= v; k++)
            for (register int i = 1; i <= v; i++)
                for (register int j = 1; j <= v; j++)
                    mp[i][j] = min(mp[i][j], mp[i][k] + mp[k][j]);
        for (register int i = 1; i <= v; i++)mp[i][i] = mp[i][0] = mp[0][i] = 0;
        for (register int i = 0; i <= n; i++)
            for (register int j = 0; j <= m; j++)dp[i][j][0] = dp[i][j][1] = inf;
        dp[1][0][0] = dp[1][1][1] = 0;
        for (register int i = 2; i <= n; i++){
            dp[i][0][0] = dp[i - 1][0][0] + mp[c[i - 1][0]][c[i][0]];
            for (register int j = 1; j <= min(i, m); j++){
                int C1 = c[i - 1][0], C2 = c[i - 1][1], C3 = c[i][0], C4 = c[i][1];
                dp[i][j][0] = min(dp[i][j][0], min(dp[i - 1][j][0] + mp[C1][C3], dp[i - 1][j][1] + mp[C1][C3] * (1 - k[i - 1]) + mp[C2][C3] * k[i - 1]));
                dp[i][j][1] = min(dp[i][j][1], min(dp[i - 1][j - 1][0] + mp[C1][C3] * (1 - k[i]) + mp[C1][C4] * k[i], dp[i - 1][j - 1][1] + mp[C2][C4] * k[i] * k[i - 1] + mp[C2][C3] * k[i - 1] * (1 - k[i]) + mp[C1][C4] * (1 - k[i - 1]) * k[i] + mp[C1][C3] * (1 - k[i - 1]) * (1 - k[i])));
            }
        }
        ans = inf;
        for (register int i = 0; i <= m; i++)ans = min(ans, min(dp[n][i][0], dp[n][i][1]));
        printf("%.2lf", ans);
        return 0;
    }
  • 相关阅读:
    Session的异常
    struts2中把action中的值传递到jsp页面的例子
    struts2中怎么把action中的值传递到jsp页面
    struts2理解
    Struts2工作原理
    第十五章 String讲解
    十六进制转十进制
    数据库综合系列 之 触发器
    android PopupWindow实现从底部弹出或滑出选择菜单或窗口
    kettle内存溢出
  • 原文地址:https://www.cnblogs.com/Invictus-Ocean/p/12934362.html
Copyright © 2020-2023  润新知