【NOIP2016提高组】换教室

https://www.luogu.org/problem/show?pid=1850

题面很长,实质很水的一道期望DP题。题面自带劝退效果。

首先用Floyd算出任意两点的最短路径。然后设f(i,j,0)为前i节课申请更换j节,且不申请第i节时的最小期望;设f(i,j,1)前i节课申请更换j节,且申请第i节时的最小期望。
可得下面这个超长的状转方程:
f(i,j,0)=min{
  f(i-1,j,0) + dist(c[i-1],c[i]),    // 不申请第i-1节
  f(i-1,j,1) + k[i-1]*dist(d[i-1],c[i]) + (1-k[i-1])*dist(c[i-1],c[i])    // 申请第i-1节
}
f(i,j,1)=min{
  f(i-1,j-1,0) + k[i]*dist(c[i-1],d[i]) + (1-k[i])*dist(c[i-1],c[i]),    // 不申请第i-1节
  f(i-1,j-1,1) + k[i-1]*k[i]*dist(d[i-1],d[i]) + (1-k[i-1])*k[i]*dist(c[i-1],d[i]) + k[i-1]*(1-k[i])*dist(d[i-1],c[i]) + (1-k[i-1])*(1-k[i])*dist(c[i-1],c[i])    // 申请第i-1节
}
注意f(i,0,0)意味着一节课都不申请,需要特判f(i,0,0)=f(i-1,0,0)+dist(c[i-1],c[i])

#include <cstdio>
#include <algorithm>
#define maxv 310
#define maxn 2010
using namespace std;
const int inf = 1000;
int v, e; // v表示牛牛学校里教室的数量;e表示牛牛的学校里道路的数量
int dist[maxv][maxv];
void add_edge(int from, int to, int weight)
{
    dist[from][to] = min(dist[from][to], weight); //注意重边和自环
    dist[to][from] = dist[from][to];
}
void floyd()
{
    // d(k,i,j)=min{d(k-1,i,j), d(k-1,i,k)+d(k-1,k,j)}
    for (int k = 1; k <= v; k++)
        for (int i = 1; i <= v; i++)
            for (int j = 1; j <= v; j++)
                dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
}
int n, m;        // n表示这个学期内的时间段的数量;m表示牛牛最多可以申请更换多少节课程的教室
int c[maxn];    // 第i个时间段牛牛被安排上课的教室
int d[maxn];    // 第i个时间段另一间上同样课程的教室
double k[maxn]; // 牛牛申请在第i个时间段更换教室获得通过的概率
void load()
{
    scanf("%d%d%d%d", &n, &m, &v, &e);
    for (int i = 1; i <= n; i++)
        scanf("%d", &c[i]);
    for (int i = 1; i <= n; i++)
        scanf("%d", &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++)
            dist[i][j] = inf;
        dist[i][i] = 0;
    }

    int tmp1, tmp2, tmp3;
    for (int i = 1; i <= e; i++)
    {
        scanf("%d%d%d", &tmp1, &tmp2, &tmp3);
        add_edge(tmp1, tmp2, tmp3);
    }
}
double dp[maxn][maxn][2];
int main()
{
    load();
    floyd();
    for (int i = 1; i <= n; i++)
    {
        dp[i][0][0] = dp[i - 1][0][0] + dist[c[i - 1]][c[i]]; // f(i,0,0)意味着一节课都不申请,需要特判
        dp[i][0][1] = 2000000;
        for (int j = 1; j <= m; j++)
        {
            // 第1~i节课,申请更换j节,且不申请第i节时的最小期望
            dp[i][j][0] = min(
                dp[i - 1][j][0] + dist[c[i - 1]][c[i]],                                                      // 不申请第i-1节
                dp[i - 1][j][1] + k[i - 1] * dist[d[i - 1]][c[i]] + (1 - k[i - 1]) * dist[c[i - 1]][c[i]] // 申请第i-1节
                );

            // 第1~i节课,申请更换j节,且申请第i节时的最小期望
            dp[i][j][1] = min(
                dp[i - 1][j - 1][0] + k[i] * dist[c[i - 1]][d[i]] + (1 - k[i]) * dist[c[i - 1]][c[i]],                                                                                                                            // 不申请第i-1节
                dp[i - 1][j - 1][1] + k[i - 1] * k[i] * dist[d[i - 1]][d[i]] + (1 - k[i - 1]) * k[i] * dist[c[i - 1]][d[i]] + k[i - 1] * (1 - k[i]) * dist[d[i - 1]][c[i]] + (1 - k[i - 1]) * (1 - k[i]) * dist[c[i - 1]][c[i]] // 申请第i-1节
                );
        }
    }
    printf("%.2f", min(dp[n][m][0], dp[n][m][1]));
    return 0;
}
时间: 2024-12-20 02:57:32

【NOIP2016提高组】换教室的相关文章

[NOIP2016提高组]换教室

题目:洛谷P1850.UOJ#262.BZOJ4720.Vijos P2005. 题目大意:有n个时间段,第i个时间段只能在教室$c_i$上课,另一个上这门课的教室在$d_i$.现在你最多可以进行m次申请,对于第i个时间段的申请如果成功,那么就能在$d_i$教室上课,但成功率为$p_i$.且教室与教室之间用e条双向道路连接,每条路有一个耗费体力的值.问申请哪几门课程可以使因在教室间移动耗费的体力值的总和的期望值最小. 解题思路:这是一道期望dp问题.对于每一时间段(第一时间段除外),我们可以分为

【NOIP2016提高组day1】?换教室

题目 对于刚上大学的牛牛来说,他面临的第一个问题是如何根据实际情况申请合适的 课程. 在可以选择的课程中,有 2n 节课程安排在 n 个时间段上. 在第 i ( 1 ≤ i ≤ n )个 时间段上,两节内容相同的课程同时在不同的地点进行,其中,牛牛预先被安排在教室 ci 上课,而另一节课程在教室 di 进行. 在不提交任何申请的情况下,学生们需要按时间段的顺序依次完成所有的 n 节安排好的课程.如果学生想更换第i节课程的教室,则需要提出申请.若申请通过,学生就可以在第 i 个时间段去教室 di

洛谷 P1850 换教室(NOIp2016提高组D1T3)

题目描述 对于刚上大学的牛牛来说,他面临的第一个问题是如何根据实际情况申请合适的课程. 在可以选择的课程中,有 2n2n 节课程安排在 nn 个时间段上.在第 ii(1 \leq i \leq n1≤i≤n)个时间段上,两节内容相同的课程同时在不同的地点进行,其中,牛牛预先被安排在教室 c_ic?i?? 上课,而另一节课程在教室 d_id?i?? 进行. 在不提交任何申请的情况下,学生们需要按时间段的顺序依次完成所有的 nn 节安排好的课程.如果学生想更换第 ii 节课程的教室,则需要提出申请.

[NOIP2012提高组]借教室

题目:洛谷P1083.Vijos P1782.codevs1217. 题目大意:有n天,每天可以借a[i]个教室.有m个请求,每个请求要在一段连续天数内借固定数目的教室.请求只能按顺序批准.求第一个无法批准的请求是第几个请求,或全部可以批准. 解题思路:看到区间,容易想到线段树维护(正解貌似是二分,燃鹅我只能理解线段树啊~).这里显然只需维护最小值.不过如果姿势不好,可是会T的哟. 线段树肯定很好写,但想不超时,就得优化.例如读入优化.标记永久化.递归过程能用全局变量用全局变量.搜到答案直接退出

【NOIP2016提高组】愤怒的小鸟(状压宽搜)

题目描述 Kiana最近沉迷于一款神奇的游戏无法自拔. 简单来说,这款游戏是在一个平面上进行的. 有一架弹弓位于(0,0)处,每次Kiana可以用它向第一象限发射一只红色的小鸟,小鸟们的飞行轨迹均为形如的曲线,其中a,b是Kiana指定的参数,且必须满足a<0. 当小鸟落回地面(即x轴)时,它就会瞬间消失. 在游戏的某个关卡里,平面的第一象限中有n只绿色的小猪,其中第i只小猪所在的坐标为(xi,yi). 如果某只小鸟的飞行轨迹经过了(xi,yi),那么第i只小猪就会被消灭掉,同时小鸟将会沿着原先

noip2016——提高组——蚯蚓

大概这题难度提高+省选-. 我也做了半天. 这题如果用优先队列做的话会时间超限. 所以就要用另一种巧妙的做法. 见代码-- 1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 using namespace std; 5 int read(){ 6 int t=1,num=0;char c=getchar(); 7 while(c>'9'||c<'0'){if(c=='-')t=-1

[NOIP2016提高组]组合数问题

题目:UOJ#263.洛谷P2822.Vijos P2006.codevs5947. 题目大意:t组数据,每次给你n和m$\leq 2000$,求对于所有的$(0\leq i\leq n)$,$(0\leq j\leq m)$的(i,j),有多少对满足$C^j_i\equiv 0(mod\ k)$. 解题思路:此题是一道数论题.首先,组合数有一个递推公式:$C^m_n=C^m_{n-1}+C^{m-1}_n$,这其实和杨辉三角的递推公式是一样的.那么我们可以预处理出所有的组合数,然后对于每一个问

NOIP2016提高组初赛(C++语言)试题 个人的胡乱分析

最近在做历年的初赛题,那我捡几道比较有代表性的题说一下好了 原题可以在这里看:https://wenku.baidu.com/view/10c0eb7ce53a580217fcfede.html?from=search 以下纯属个人胡乱分析,不爽不要看(误 单项选择 T2.一只小老鼠在键盘的Caps Lock键,A键,S键,D键上跳来跳去,问屏幕上输出的第81个字符. 显然是有周期性的,ASDSAasdsa为一个周期,可以得知T=10,所以第81个字符字符为81 % 10 = 1,即第一个字符A

【NOIP2016提高组A组7.16】大鱼海棠

题目 椿是掌管海棠花的少女,她所在的世界不为人们所知,他们的天空就是人类的海底.生活在那个世界里的他们不是人,也不是鱼,而是其他人,掌管着人间的规律. 按照他们的习俗,在16岁那年,椿变为一条海豚到人间巡礼.在第六天,她被大海中的一张网困住,一个人类男孩因为救她而落入深海死去.为了报恩,她回去后私自一人去了如升楼找到灵婆(死去的好人的灵魂化为一条小鱼安放在那里).她以自己一般的寿命为代价,与灵婆换得了男孩的灵魂,从此她和男孩性命相连.她必须背着族人将拇指大的小鱼养大为比鲸还要大的鲲,并将它放归人