zoukankan      html  css  js  c++  java
  • P1850 换教室 概率dp

    其实说是概率dp,本质上和dp没什么区别,就是把所有可能转移的情况全枚举一下就行了,不过dp方程确实有点长。。。

    ps:这个题的floyed我竟然之前写跪了。。。

    题目:

    题目描述
    
    对于刚上大学的牛牛来说,他面临的第一个问题是如何根据实际情况申请合适的课程。
    
    在可以选择的课程中,有 2n2n2n 节课程安排在 nnn 个时间段上。在第 iii(1≤i≤n1 leq i leq n1≤i≤n)个时间段上,两节内容相同的课程同时在不同的地点进行,其中,牛牛预先被安排在教室 cic_ici​ 上课,而另一节课程在教室 did_idi​ 进行。
    
    在不提交任何申请的情况下,学生们需要按时间段的顺序依次完成所有的 nnn 节安排好的课程。如果学生想更换第 iii 节课程的教室,则需要提出申请。若申请通过,学生就可以在第 iii 个时间段去教室 did_idi​ 上课,否则仍然在教室 cic_ici​ 上课。
    
    由于更换教室的需求太多,申请不一定能获得通过。通过计算,牛牛发现申请更换第 iii 节课程的教室时,申请被通过的概率是一个已知的实数 kik_iki​,并且对于不同课程的申请,被通过的概率是互相独立的。
    
    学校规定,所有的申请只能在学期开始前一次性提交,并且每个人只能选择至多 mmm 节课程进行申请。这意味着牛牛必须一次性决定是否申请更换每节课的教室,而不能根据某些课程的申请结果来决定其他课程是否申请;牛牛可以申请自己最希望更换教室的 mmm 门课程,也可以不用完这 mmm 个申请的机会,甚至可以一门课程都不申请。
    
    因为不同的课程可能会被安排在不同的教室进行,所以牛牛需要利用课间时间从一间教室赶到另一间教室。
    
    牛牛所在的大学有 vvv 个教室,有 eee 条道路。每条道路连接两间教室,并且是可以双向通行的。由于道路的长度和拥堵程度不同,通过不同的道路耗费的体力可能会有所不同。 当第 iii(1≤i≤n−11 leq i leq n-11≤i≤n−1)节课结束后,牛牛就会从这节课的教室出发,选择一条耗费体力最少的路径前往下一节课的教室。
    
    现在牛牛想知道,申请哪几门课程可以使他因在教室间移动耗费的体力值的总和的期望值最小,请你帮他求出这个最小值。
    输入输出格式
    输入格式:
    
    第一行四个整数 n,m,v,en,m,v,en,m,v,e。nnn 表示这个学期内的时间段的数量;mmm 表示牛牛最多可以申请更换多少节课程的教室;vvv 表示牛牛学校里教室的数量;eee表示牛牛的学校里道路的数量。
    
    第二行 nnn 个正整数,第 iii(1≤i≤n1 leq i leq n1≤i≤n)个正整数表示 cic_ici​,即第 iii 个时间段牛牛被安排上课的教室;保证 1≤ci≤v1 le c_i le v1≤ci​≤v。
    
    第三行 nnn 个正整数,第 iii(1≤i≤n1 leq i leq n1≤i≤n)个正整数表示 did_idi​,即第 iii 个时间段另一间上同样课程的教室;保证 1≤di≤v1 le d_i le v1≤di​≤v。
    
    第四行 nnn 个实数,第 iii(1≤i≤n1 leq i leq n1≤i≤n)个实数表示 kik_iki​,即牛牛申请在第 iii 个时间段更换教室获得通过的概率。保证 0≤ki≤10 le k_i le 10≤ki​≤1。
    
    接下来 eee 行,每行三个正整数 aj,bj,wja_j, b_j, w_jaj​,bj​,wj​,表示有一条双向道路连接教室 aj,bja_j, b_jaj​,bj​,通过这条道路需要耗费的体力值是 wjw_jwj​;保证 1≤aj,bj≤v1 le a_j, b_j le v1≤aj​,bj​≤v, 1≤wj≤1001 le w_j le 1001≤wj​≤100。
    
    保证 1≤n≤20001 leq n leq 20001≤n≤20000≤m≤20000 leq m leq 20000≤m≤20001≤v≤3001 leq v leq 3001≤v≤3000≤e≤900000 leq e leq 900000≤e≤90000。
    
    保证通过学校里的道路,从任何一间教室出发,都能到达其他所有的教室。
    
    保证输入的实数最多包含 333 位小数。
    
    输出格式:
    
    输出一行,包含一个实数,四舍五入精确到小数点后恰好222位,表示答案。你的输出必须和标准输出完全一样才算正确。
    
    测试数据保证四舍五入后的答案和准确答案的差的绝对值不大于 4×1034 	imes 10^{-3}4×103。 (如果你不知道什么是浮点误差,这段话可以理解为:对于大多数的算法,你可以正常地使用浮点数类型而不用对它进行特殊的处理)
    
    输入输出样例
    输入样例#1: 复制
    
    3 2 3 3
    2 1 2
    1 2 1
    0.8 0.2 0.5 
    1 2 5
    1 3 3
    2 3 1
    
    输出样例#1: 复制
    
    2.80
    
    说明
    
    【样例1说明】
    
    所有可行的申请方案和期望收益如下表:
    
    【提示】
    
        道路中可能会有多条双向道路连接相同的两间教室。 也有可能有道路两端连接的是同一间教室。
    
        请注意区分n,m,v,e的意义, n不是教室的数量, m不是道路的数量。
    
    特殊性质1:图上任意两点 aia_iai​, bib_ibi​, aia_iai​≠ bib_ibi​间,存在一条耗费体力最少的路径只包含一条道路。
    
    特殊性质2:对于所有的 1≤i≤n1≤ i≤ n1≤i≤n, ki=1k_i= 1ki​=1
    题目-

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<ctime>
    #include<queue>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    #define duke(i,a,n) for(int i = a;i <= n;i++)
    #define lv(i,a,n) for(int i = a;i >= n;i--)
    #define clean(a) memset(a,0,sizeof(a))
    const int INF = 1e9 + 7;
    typedef long long ll;
    typedef double db;
    template <class T>
    void read(T &x)
    {
        char c;
        bool op = 0;
        while(c = getchar(), c < '0' || c > '9')
            if(c == '-') op = 1;
        x = c - '0';
        while(c = getchar(), c >= '0' && c <= '9')
            x = x * 10 + c - '0';
        if(op) x = -x;
    }
    template <class T>
    void write(T x)
    {
        if(x < 0) putchar('-'), x = -x;
        if(x >= 10) write(x / 10);
        putchar('0' + x % 10);
    }
    const int N = 2010;
    int n,m,v,e;
    int c[N],d[N];
    db k[N];
    db mp[N][N];
    db dp[N][N][2];
    int main()
    {
        read(n);read(m);read(v);read(e);
        duke(i,1,n)
        {
            read(c[i]);
        }
        duke(i,1,n)
        {
            read(d[i]);
        }
        duke(i,1,n)
        {
            scanf("%lf",&k[i]);
        }
        duke(i,1,v)
        {
            duke(j,1,v)
            {
                mp[i][j] = INF;
            }
        }
        duke(i,1,e)
        {
            int x,y;
            db w;
            read(x);read(y);scanf("%lf",&w);
            if(w < mp[x][y])
            {
                mp[x][y] = w;
                mp[y][x] = w;
            }
        }
        duke(i,0,n)
        {
            duke(j,0,m)
            dp[i][j][0] = dp[i][j][1] = INF / 4;
        }
        duke(i,1,v)
        {
            mp[i][i] = mp[i][0] = mp[0][i] = 0;
        }
        duke(l,1,v)
        {
            duke(i,1,v)
            {
                duke(j,1,v)
                {
    //                if(i != j && j != l && i != l)
                    {
                        mp[i][j] = min(mp[i][j],mp[i][l] + mp[l][j]);
                    }
                }
            }
        }
        dp[1][0][0] = 0,dp[1][1][1] = 0;
        for(int i = 2;i <= n;i++)
        {
            dp[i][0][0] = dp[i - 1][0][0] + mp[c[i - 1]][c[i]];
            for(int j = 1;j <= min(i,m);j++)
            {
                dp[i][j][0] = min(dp[i][j][0],min(dp[i - 1][j][0] + mp[c[i - 1]][c[i]],dp[i - 1][j][1] + mp[c[i - 1]][c[i]] * (1 - k[i - 1]) + mp[d[i - 1]][c[i]] * k[i - 1]));
                dp[i][j][1] = min(dp[i][j][1],min(dp[i - 1][j - 1][0] + mp[c[i - 1]][c[i]] * (1 - k[i]) + mp[c[i - 1]][d[i]] * k[i],dp[i - 1][j - 1][1] + mp[d[i - 1]][d[i]] * k[i] * k[i - 1] + mp[d[i - 1]][c[i]] * (1 - k[i]) * k[i - 1] + mp[c[i - 1]][d[i]] * (1 - k[i - 1]) * k[i] + mp[c[i - 1]][c[i]] * (1 - k[i]) * (1 - k[i - 1])));
            }
        }
        db ans = INF / 4;
        duke(i,0,m)
        {
            ans = min(ans,min(dp[n][i][0],dp[n][i][1]));
        }
        printf("%.2lf
    ",ans);
        return 0;
    }
  • 相关阅读:
    资源:mysql下载路径
    知识点:jar包与war包的差异
    Linux:jar服务部署
    Flyway:Spring Boot中使用Flyway来管理数据库版本
    Java:Java控制台输出保存进文件
    Maven:手动添加jar包进Maven本地库内
    Https:SSL双向认证机制(理论知识)
    Linux ubuntu 下寻找 texlive 缺失包 texlive 缺失包(转载)
    Android应用开发提高篇(4)-----Socket编程(多线程、双向通信)(转载)
    Android应用开发基础篇(12)-----Socket通信(转载)
  • 原文地址:https://www.cnblogs.com/DukeLv/p/9595450.html
Copyright © 2011-2022 走看看