ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

P1850 [NOIP2016 提高组] 换教室 题解

2022-05-28 11:01:30  阅读:132  来源: 互联网

标签:NOIP2016 ch 题解 教室 时间段 dp P1850 丽莎 可爱


题目大意

有 \(n\) 个时间段,有 \(2n\) 个课程,在第 \(i\) 个时间段的时候,有两个教室 \(c_i\) 和 \(d_i\) ,第 \(i\) 个时间段申请换教室通过的概率为 \(k_i\)。

可以选择 \(m\) 个时间段进行换教室,也可以换不到 \(m\) 个教室。

所在大学是一个 \(v\) 个点,\(e\) 条边的图,由双向边连接,通过每条路的消耗体力不一样,要求最小化申请后在教室之间移动的体力值总和的期望。

\(\text{Data Range:} 1 \leq m \leq n \leq 2000,v \leq 300\)。


首先要求一个任意两点之间最短路,这个可以直接 \(v^3\) 的 \(\text{Floyd}\) 进行预处理,用 \(dis_{u,v}\) 表示点 \(u\) 和点 \(v\) 之间的最短路。

然后考虑设立 \(dp_{i,j,0/1}\) 表示前 \(i\) 个时间段中,有 \(j\) 个时间段换了教室,我当前换没换教室的期望消费体力。

转移,直接转移:

\[dp_{i,j,0} = \min(dp_{i-1,j,0} + dis_{c_{i-1},c_i}, dp_{i-1,j,1} + k_{i-1}\times dis_{d_{i-1},c_i} + (1 - k_{i - 1}) \times dis_{c_{i-1}, c_i}) \]

\(dp_{i,j,1}\) 的转移更着上面的方式也能写出来吧,但是写出来太长了,就没打公式了,可以直接代码,反正就四种情况讨论一下,然后直接转移就好了。


// 德丽莎你好可爱德丽莎你好可爱德丽莎你好可爱德丽莎你好可爱德丽莎你好可爱
// 德丽莎的可爱在于德丽莎很可爱,德丽莎为什么很可爱呢,这是因为德丽莎很可爱!
#include <bits/stdc++.h>
#define int long long
using namespace std;
inline int read() {
  int x = 0, f = 1;  char ch = getchar();
  while( !isdigit(ch) ) { if(ch == '-') f = -1;  ch = getchar();  }
  while( isdigit(ch) ) {  x = (x << 1) + (x << 3) + (ch ^ 48);  ch = getchar();  }
  return x * f;
}
const int N = 2e5, inf = 1e17;
int n, m, v, e, c[N], d[N];
double k[N], dp[3005][3005][2], ans = inf, dis[305][305];
void chkmin(double &x,double y) { if (y < x) x = y; }
signed main () {
  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 <= v; i++) 
    for (int j = 1; j <= v; j++)
      dis[i][j] = inf;
  for (int i = 1; i <= e; i++) {
    int a = read(), b = read(), c = read();
    dis[a][b] = dis[b][a] = min(dis[a][b], (double)c);
  }
  for (int k = 1; k <= v; k++)
    for (int i = 1; i <= v; i++)
      for (int j = 1; j <= v; j++)
        dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
  for (int i = 1; i <= v; i++) dis[i][0] = dis[0][i] = dis[i][i] = 0;
  for (int i = 0; i <= n; i++) 
    for (int j = 0; j <= m; j++)
      dp[i][j][0] = dp[i][j][1] = inf;
  dp[1][1][1] = dp[1][0][0] = 0;
  for (int i = 2; i <= n; i++) {
    dp[i][0][0] = dp[i - 1][0][0] + dis[c[i - 1]][c[i]];
    for (int j = 1; j <= min(i, m); j++) {
      chkmin(dp[i][j][0], dp[i - 1][j][0] + dis[c[i - 1]][c[i]]);
      chkmin(dp[i][j][0], dp[i - 1][j][1] + (double) (1.0 - k[i - 1]) * dis[c[i - 1]][c[i]] + (double) k[i - 1] * dis[d[i - 1]][c[i]]);
      chkmin(dp[i][j][1], dp[i - 1][j - 1][0] + (double) (1.0 - k[i]) * dis[c[i - 1]][c[i]] + (double) k[i] * dis[c[i - 1]][d[i]] );
      chkmin(dp[i][j][1], dp[i - 1][j - 1][1] + (double) k[i - 1] * k[i] * dis[d[i - 1]][d[i]] + (double) k[i - 1] * (1.0 - k[i]) * dis[d[i - 1]][c[i]] + (double) (1.0 - k[i - 1]) * (1.0 - k[i]) * dis[c[i - 1]][c[i]] + (double) (1.0 - k[i - 1]) * k[i] * dis[c[i - 1]][d[i]] );
    }
  }
  for (int i = 0; i <= m; i++) {
    ans = min(ans, dp[n][i][0]); ans = min(ans, dp[n][i][1]);
  }
  printf("%.2lf\n", ans);
  return 0;
}

标签:NOIP2016,ch,题解,教室,时间段,dp,P1850,丽莎,可爱
来源: https://www.cnblogs.com/orzpls/p/16320057.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有