【DP】【期望】$P1850$换教室

【DP】【期望】\(P1850\)换教室

链接

题目描述

有 \(2n\) 节课程安排在$ n$ 个时间段上。在第 \(i\)(\(1 \leq i \leq n\))个时间段上,两节内容相同的课程同时在不同的地点进行,其中,牛牛预先被安排在教室 \(c_i\)上课,而另一节课程在教室 \(d_i\)进行。

在不提交任何申请的情况下,学生们需要按时间段的顺序依次完成所有的 \(n\)节安排好的课程。如果学生想更换第 \(i\)节课程的教室,则需要提出申请。若申请通过,学生就可以在第 $i $个时间段去教室 \(d_i\) 上课,否则仍然在教室 \(c_i\)上课。

牛牛发现申请更换第\(i\)节课程的教室时,申请被通过的概率是一个已知的实数 \(k_i\),并且对于不同课程的申请,被通过的概率是互相独立的。

所有的申请只能一次性提交,并且每个人只能选择至多 \(m\)节课程进行申请。

牛牛所在的大学有 \(v\)个教室,有 \(e\) 条道路。每条道路连接两间教室,并且是可以双向通行的。由于道路的长度和拥堵程度不同,通过不同的道路耗费的体力可能会有所不同。 当第 \(i\)(\(1 \leq i \leq n-1\))节课结束后,牛牛就会从这节课的教室出发,选择一条耗费体力最少的路径前往下一节课的教室。

现在牛牛想知道,申请哪几门课程可以使他因在教室间移动耗费的体力值的总和的期望值最小。

输入格式

第一行四个整数 \(n,m,v,e\)。

第二行 \(n\) 个正整数,第 \(i\)(\(1 \leq i \leq n\))个正整数表示 c\(c_i\),即第\(i\)个时间段牛牛被安排上课的教室;保证 \(1 \le c_i \le v\)。

第三行 \(n\) 个正整数,第 \(i\)(\(1 \leq i \leq n\))个正整数表示 \(d_i\),即第 $i $个时间段另一间上同样课程的教室;保证 \(1 \le d_i \le v\)。

第四行 \(n\) 个实数,第 \(i\)(\(1 \leq i \leq n\))个实数表示 \(k_i\),即牛牛申请在第 \(i\)个时间段更换教室获得通过的概率。保证 \(0 \le k_i \le 1\)。

接下来 \(e\) 行,每行三个正整数 \(a_j, b_j, w_j\),表示有一条双向道路连接教室 \(a_j, b_j\),通过这条道路需要耗费的体力值是 \(w_j\);保证 \(1 \le a_j, b_j \le v\), \(1 \le w_j \le 100\)。

保证 \(1 \leq n \leq 2000\),\(0 \leq m \leq 2000\),\(1 \leq v \leq 300\),\(0 \leq e \leq 90000\)。

保证通过学校里的道路,从任何一间教室出发,都能到达其他所有的教室。

保证输入的实数最多包含 \(3\)位小数。

输出格式

输出一行,包含一个实数,四舍五入精确到小数点后恰好\(2\)位,表示答案。你的输出必须和标准输出完全一样才算正确。

测试数据保证四舍五入后的答案和准确答案的差的绝对值不大于 \(4 \times 10^{-3}\)。 (如果你不知道什么是浮点误差,这段话可以理解为:对于大多数的算法,你可以正常地使用浮点数类型而不用对它进行特殊的处理)

样例

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
2.80

提示

  1. 道路中可能会有多条双向道路连接相同的两间教室。 也有可能有道路两端连接的是同一间教室。
  2. 请注意区分\(n,m,v,e\)的意义, \(n\)不是教室的数量, \(m\)不是道路的数量。

\(Solution\)

考虑DP。状态怎么设?显然第几节课需要在状态里。还要保证最多换\(m\)次,因此次数也要在状态里。那么,怎么从上一节课转移呢?显然如果我们不知道上一节课在哪个教室上的,就无法转移。因此,还要在加一维,记录当前是否申请换教室。

因此,状态就是\(f[i][j][k], 1 \leq i \leq n, 0 \leq j \leq m, 0 \leq k \leq 1\),表示前\(i\)节课,换了\(j\)次教室,第\(i\)次换或不换的期望。

至于转移则比较简单了

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

如图为当前不选择换教室

如图为当前选择换教室

这道题还有几点需要主意的,在预处理部分。具体看代码

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
long long read(){
  long long x = 0; int f = 0; char c = getchar();
  while(c < '0' || c > '9') f |= c == '-', c = getchar();
  while(c >= '0' && c <= '9') x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
  return f? -x:x;
}

int n, m, V, E, c[2002], d[2002], w[305][305];
double f[2002][2002][2], k[2002], ans;
int main(){
  memset(w, 63, sizeof w);//距离初始化
  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();
  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();
    w[x][y] = w[y][x] = min(w[x][y], z);//有可能重边
  }
  for(int l = 1; l <= V; ++l)
    for(int i = 1; i <= V; ++i)
      for(int j = 1; j <= V; ++j)
        w[i][j] = min(w[i][j], w[i][l] + w[l][j]);//floyed最短路
  for(int i = 1; i <= V; ++i) w[i][i] = w[i][0] = w[0][i] = 0;//初始化
  for(int i = 1; i <= n; ++i) f[i][0][0] = f[i - 1][0][0] + w[c[i]][c[i - 1]], f[i][0][1] = 1e9;
    //初始化,处理一个也不申请的情况
  for(int i = 1; i <= n; ++i)
    for(int j = 1; j <= m; ++j){
      f[i][j][0] = min(f[i - 1][j][0] + w[c[i]][c[i - 1]],
                       f[i - 1][j][1] + w[c[i]][d[i - 1]] * k[i - 1]
                        + w[c[i]][c[i - 1]] * (1 - k[i - 1]));
      f[i][j][1] = min(f[i - 1][j - 1][0] + w[c[i]][c[i - 1]] * (1 - k[i])
                       + w[d[i]][c[i - 1]] * k[i],
                      f[i - 1][j - 1][1] + w[d[i]][d[i - 1]] * k[i - 1] * k[i]
                      + w[c[i]][c[i - 1]] * (1 - k[i - 1]) * (1 - k[i])
                      + w[c[i - 1]][d[i]] * (1 - k[i - 1]) * k[i]
                      + w[d[i - 1]][c[i]] * k[i - 1] * (1 - k[i]));
    }
  double ans = f[n][0][0];
  for(int i = 1; i <= m; ++i) ans = min(ans, min(f[n][i][1], f[n][i][0]));//更新答案
  printf("%.2lf", ans);
  return 0;
} 

原文地址:https://www.cnblogs.com/kylinbalck/p/11258482.html

时间: 2024-08-04 05:15:25

【DP】【期望】$P1850$换教室的相关文章

[NOIP2016]换教室 D1 T3 Floyed+期望DP

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

Luogu P1850 换教室(期望dp)

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

【niop2016】【luogu1600】换教室[概率dp]

luogu1600 假设{ Bn | n = 1, 2, 3, ... } 是一个概率空间的有限或者可数无限的分割,且每 个集合 Bn 是一个可测集合,则对任意事件 A 有全概率公式: 一下来自  贼清晰!简直是一朵清奇的白莲花 f[i][j][0/1]表示前i个时间点,共申请了j次,第i个时间点否/是进行了申请. dis[a][b]表示a教室->b教室的距离 c[i]表示默认的教室 d[i]表示更换后的教室 k[i]表示第i个教室申请成功的概率 分类讨论主要分成两大类,4小类,最后分成9个小项

BZOJ 4720 [Noip2016]换教室

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

[BZOJ 4720][NOIP 2016] 换教室

记得某dalao立了"联赛要是考概率期望我直播吃键盘"的$flag$然后就有了这道题233333 4720: [Noip2016]换教室 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 879  Solved: 461[Submit][Status][Discuss] Description 对于刚上大学的牛牛来说,他面临的第一个问题是如何根据实际情况申请合适的课程.在可以选择的课程中,有2n节课程安排在n个时间段上. 在第i(1≤i≤n

P1850 换教室

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

洛谷P1850 换教室 最短路 + 动态规划

洛谷P1850 换教室最短路 + 动态规划 题解 首先预处理出任意两点的最短路 然后 dp f[ i ][ j ][ 0/1 ] 现在是 第 i 个时间段,已经申请 过 j次了,该次是否成功 0 否 1 成功 的最小的期望 主要是四个方面的转移 前一个是否申请 成功 or失败 当前是否申请 成功or失败 1 #include <bits/stdc++.h> 2 #define For(i,j,k) for(int i=j;i<=k;i++) 3 using namespace std ;

Noip2016 换教室(数学期望入门)

题意:有2n个课程安排在n个时间段上,在第i个时间被安排在ci教室上课,但牛牛可以申请换教室,到di教室上课,但只有pi的可能成功.学校有v个教室,e条道路,每条路双向连通,每条路都会消耗一定的体力wi(保证每个教室可以互相到达),问牛牛应该怎么安排,才能使总花费的体力的期望值最小. 输入格式: 第一行四个整数n,m,v,e.n表示时间短的数量:m表示最多可以申请更换教室的数量:v表示教室的数量:e表示道路的数量. 第二行n个正整数,第i个表示ci: 第三行n个正整数,第i个表示di: 第四行n

noip 2016 换教室

第一个 完全自己想的期望+完全自己做的T3    并且  +1遍AC Description: luogu 换教室 Solution: 一看是一道期望题. 再一看,发现,v<=300,n,m<=2000有点意思. 大概复杂度n^2确定. 有一张图?任意两点间最短路?300就是floyd的提示嘛!! 预处理floyd确定. 发现,阶段比较明显,第i个阶段 一看就是一道期望dp题了. dp状态:显然要记录第i阶段,显然要知道用了几个申请.恰好n方开的下. 可以设dp[i][j],表示前i阶段,包括