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

题目大意

n 个时间段,有 2n 个课程,在第 i 个时间段的时候,有两个教室 cidi ,第 i 个时间段申请换教室通过的概率为 ki

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

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

Data Range:1mn2000,v300


首先要求一个任意两点之间最短路,这个可以直接 v3Floyd 进行预处理,用 disu,v 表示点 u 和点 v 之间的最短路。

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

转移,直接转移:

dpi,j,0=min(dpi1,j,0+disci1,ci,dpi1,j,1+ki1×disdi1,ci+(1ki1)×disci1,ci)

dpi,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;
}
posted @   Pitiless0514  阅读(49)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示