zoukankan      html  css  js  c++  java
  • 「NOIP 2016」换教室

    Description

    (n) 节课,第 (i) 节课可以选择在教室 (C_i) 上课,也可以选择申请换教室,到教室 (D_i) 上课。若选择申请换课,则有 (K_i) 的概率申请通过,另外 (1-K_i) 的概率依然留在 (C_i) 教室。

    共有 (v) 个教室,(e) 条路径双向连通教室 (X_i)(Y_i),边权为 (W_i)。在每两节课之间,你要从上一个教室走到下一个教室。

    最多提交 (m) 个申请,并且得在第一节课上课之前一次性提交所有申请(也就是,不能根据某一次申请的通过情况来选择下一次申请),要使自己走的路的期望最小。求最优策略下的总距离的期望。

    (1leq nleq 2000,0leq m leq 2000,1leq vleq 300,0leq eleq 9 imes 10^4,1leq W_i leq 1000,0leq K_ileq 1)

    Solution

    考虑 DP,用 (dp_{i,j,0/1}) 表示前 (i) 节课申请了 (j) 次,第 (i) 次是否申请的期望最小值。

    先用 Floyd 预处理出两个教室之间的最短路长度 (dis(i,j))

    (dp_{i,j,0}) 所记录的状态一定处在教室 (c_i)(dp_{i,j,1}) 所记录的状态有 (k_i) 的概率处在 (d_i),另 (1-k_i) 的概率处在 (c_i)

    讨论第 (i) 次是否申请。(P_1,P_2) 是临时变量,分别存第 (i-1) 节课“申请/不申请”两种方案的期望总距离。

    若不申请:

    • (P_1=dp_{i-1,j,0}+dis(c_{i-1},c[i]))
    • (P_2=dp_{i-1,j,1}+k_{i-1} imes dis(d_{i-1},c_i)+(1-k_{i-1}) imes dis(c_{i-1},c_i))

    (dp_{i,j,0}=min(P_1,P_2))

    即在两种策略中选取期望值较小的。

    若申请:

    • (P_1=dp_{i-1,j-1,0}+k_i imes dis(c_{i-1},d_i)+(1-k_i) imes dis(c_{i-1},c_i))
    • (P_2=dp_{i-1,j-1,1}+(1-k_{i-1}) imes k_i imes dis(c_{i-1},d_i)+(1-k_{i-1}) imes (1-k_i) imes dis(c_{i-1},c_i)\+k_{i-1} imes k_i imes dis(d_{i-1},d_i)+k_{i-1} imes (1-k_i) imes dis(d_{i-1},c_i))

    (dp_{i,j,1}=min(P_1,P_2))

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    const int N=2010,M=310,inf=1e18;
    int n,m,v,e,c[N],d[N],x,y,z,f[M][M];
    double k[N],dp[N][N][2],p1,p2,ans=inf; 
    signed main(){
        scanf("%lld%lld%lld%lld",&n,&m,&v,&e);
        for(int i=1;i<=n;i++)
            scanf("%lld",&c[i]);
        for(int i=1;i<=n;i++)
            scanf("%lld",&d[i]);
        for(int i=1;i<=n;i++)
            scanf("%lf",&k[i]);
        //初始化两点之间的最短路 
        for(int i=1;i<=v;i++)
            for(int j=1;j<=v;j++)
                f[i][j]=f[j][i]=inf;
        for(int i=1;i<=e;i++){
            scanf("%lld%lld%lld",&x,&y,&z);
            f[x][y]=f[y][x]=min(f[x][y],z); 
        }
        for(int i=1;i<=v;i++)
            for(int j=1;j<=v;j++) f[i][i]=0;
        //floyd 求任意两点之间的最短路 
        for(int k=1;k<=v;k++)
            for(int i=1;i<=v;i++)
                for(int j=1;j<=v;j++)
                    f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
        //初始化期望 
        for(int i=0;i<=n;i++)
            for(int j=0;j<=m;j++)
                dp[i][j][0]=dp[i][j][1]=inf;    //DP 之前的初值概率均为无穷大便于比较
        //DP 计算期望 
        dp[1][0][0]=dp[1][1][1]=0;    //DP 初值 
        for(int i=2;i<=n;i++)
            for(int j=0;j<=min(i,m);j++){
                p1=dp[i-1][j][0]+f[c[i-1]][c[i]],p2=dp[i-1][j][1]+k[i-1]*f[d[i-1]][c[i]]+(1-k[i-1])*f[c[i-1]][c[i]];
                dp[i][j][0]=min(dp[i][j][0],min(p1,p2));
                if(j){
                    p1=dp[i-1][j-1][0]+k[i]*f[c[i-1]][d[i]]+(1-k[i])*f[c[i-1]][c[i]];
                    p2=dp[i-1][j-1][1]+(1-k[i-1])*k[i]*f[c[i-1]][d[i]]+(1-k[i-1])*(1-k[i])*f[c[i-1]][c[i]]+k[i-1]*k[i]*f[d[i-1]][d[i]]+k[i-1]*(1-k[i])*f[d[i-1]][c[i]];
                    dp[i][j][1]=min(dp[i][j][1],min(p1,p2));
                } 
            }
        //计算答案 
        for(int i=0;i<=m;i++)
            ans=min(ans,min(dp[n][i][0],dp[n][i][1]));
        printf("%.2lf
    ",ans);
        return 0;
    } 
  • 相关阅读:
    记录输出时间
    ***灵感或者没想到的思想
    Managing Difficulties
    4.20
    单调队列
    背包
    线性DP
    可持久化数据结构
    平衡树
    点分治
  • 原文地址:https://www.cnblogs.com/maoyiting/p/13454610.html
Copyright © 2011-2022 走看看