题目描述

对于刚上大学的牛牛来说,他面临的第一个问题是如何根据实际情况申请合适的课程。

在可以选择的课程中,有 2n2n 节课程安排在 nn 个时间段上。在第 ii(1 \leq i \leq n1≤i≤n)个时间段上,两节内容相同的课程同时在不同的地点进行,其中,牛牛预先被安排在教室 c_ici​ 上课,而另一节课程在教室 d_idi​ 进行。

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

由于更换教室的需求太多,申请不一定能获得通过。通过计算,牛牛发现申请更换第 ii 节课程的教室时,申请被通过的概率是一个已知的实数 k_iki​,并且对于不同课程的申请,被通过的概率是互相独立的。

学校规定,所有的申请只能在学期开始前一次性提交,并且每个人只能选择至多 mm 节课程进行申请。这意味着牛牛必须一次性决定是否申请更换每节课的教室,而不能根据某些课程的申请结果来决定其他课程是否申请;牛牛可以申请自己最希望更换教室的 mm 门课程,也可以不用完这 mm 个申请的机会,甚至可以一门课程都不申请。

因为不同的课程可能会被安排在不同的教室进行,所以牛牛需要利用课间时间从一间教室赶到另一间教室。

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

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

输入输出格式

输入格式:

第一行四个整数 n,m,v,en,m,v,e。nn 表示这个学期内的时间段的数量;mm 表示牛牛最多可以申请更换多少节课程的教室;vv 表示牛牛学校里教室的数量;ee表示牛牛的学校里道路的数量。

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

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

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

接下来 ee 行,每行三个正整数 a_j, b_j, w_jaj​,bj​,wj​,表示有一条双向道路连接教室 a_j, b_jaj​,bj​,通过这条道路需要耗费的体力值是 w_jwj​;保证 1 \le a_j, b_j \le v1≤aj​,bj​≤v, 1 \le w_j \le 1001≤wj​≤100。

保证 1 \leq n \leq 20001≤n≤2000,0 \leq m \leq 20000≤m≤2000,1 \leq v \leq 3001≤v≤300,0 \leq e \leq 900000≤e≤90000。

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

保证输入的实数最多包含 33 位小数。

输出格式:

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

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

输入输出样例

输入样例#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说明】

所有可行的申请方案和期望收益如下表:

【提示】

  1. 道路中可能会有多条双向道路连接相同的两间教室。 也有可能有道路两端连接

的是同一间教室。

2.请注意区分n,m,v,e的意义, n不是教室的数量, m不是道路的数量。

特殊性质1:图上任意两点 a_iai​, b_ibi​, a_iai​≠ b_ibi​间,存在一条耗费体力最少的路径只包含一条道路。

特殊性质2:对于所有的 $1≤ i≤ n$, k_i= 1ki​=1 。

483 055 310

思路:概率DP

总结一下暴力的几次wa的原因:

1.dis赋最大值的时候,附的这个:memset(dis,0x7f,sizeof(dis));

在之后的floyed中 dis相加 爆了long long 所以改成这个 memset(dis,0x3f,sizeof(dis)); 就可以了。

2.第78行,输入的时候,可能有重边,所以应该对一条路径的所有dis值取小。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 20100
using namespace std;
int sum;
int n,m,v,e;
double k[MAXN];
int dis[][];
double ans=0x7f7f7f7f,bns,cns;
int c[MAXN],d[MAXN],vis[MAXN],vis1[MAXN];
void dfs1(int tot,int num,int now){
if(num>tot) return ;
if(tot==num){
int len=,pre;double p=;
for(int i=;i<=n;i++)
if(vis[i]&&!vis1[i]){
if(i==) pre=c[i];
len+=dis[pre][c[i]];
pre=c[i];
p*=(-k[i]);
}
else if(vis[i]&&vis1[i]){
if(i==) pre=d[i];
len+=dis[pre][d[i]];
pre=d[i];
p*=k[i];
}
else{
if(i==) pre=c[i];
len+=dis[pre][c[i]];
pre=c[i];
}
cns+=len*p;
return ;
}
for(int i=now+;i<=n;i++)
if(vis[i]&&!vis1[i]){
vis1[i]=;
dfs1(tot,num+,i);
vis1[i]=;
}
}
void work(int tot){
bns=;
for(int i=;i<=tot;i++){
cns=;
dfs1(i,,);
bns+=cns;
}
}
void dfs(int tot,int num,int now){
if(num>tot) return ;
if(tot==num){
work(tot);//第二重dfs暴力确定期望最小距离。
ans=min(ans,bns);
return ;
}
for(int i=now+;i<=n;i++)
if(!vis[i]){
vis[i]=;
dfs(tot,num+,i);
vis[i]=;
}
}
int main(){
freopen("classrooma.in","r",stdin);
freopen("classrooma.out","w",stdout);
memset(dis,0x3f,sizeof(dis));
scanf("%d%d%d%d",&n,&m,&v,&e);
for(int i=;i<=n;i++) scanf("%d",&c[i]);
for(int i=;i<=n;i++) scanf("%d",&d[i]);
for(int i=;i<=n;i++) scanf("%lf",&k[i]);
for(int i=;i<=e;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
dis[x][y]=dis[y][x]=min(dis[x][y],z);
}
for(int i=;i<=v;i++) dis[i][i]=;
/*floyed 预处理距离*/
for(int k=;k<=v;k++)
for(int i=;i<=v;i++)
for(int j=;j<=v;j++)
if(i!=k&&k!=j&&dis[i][j]>dis[i][k]+dis[k][j])
dis[i][j]=dis[i][k]+dis[k][j]; for(int i=;i<=m;i++){
sum=;
memset(vis,,sizeof(vis));
dfs(i,,);//第一重dfs选择换那几间。
}
printf("%.2lf",ans);
}

80分的暴力

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 2010
using namespace std;
double ans=0x7f7f7f7f;
int n,m,v,e;
double k[MAXN];
int dis[][];
int c[MAXN],d[MAXN];
double f[MAXN][MAXN][];
int main(){
// freopen("classrooma.in","r",stdin);
// freopen("classrooma.out","w",stdout);
memset(dis,0x3f,sizeof(dis));
scanf("%d%d%d%d",&n,&m,&v,&e);
for(int i=;i<=n;i++) scanf("%d",&c[i]);
for(int i=;i<=n;i++) scanf("%d",&d[i]);
for(int i=;i<=n;i++) scanf("%lf",&k[i]);
for(int i=;i<=e;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
dis[x][y]=dis[y][x]=min(dis[x][y],z);
}
for(int i=;i<=v;i++) dis[i][i]=;
for(int kk=;kk<=v;kk++)
for(int i=;i<=v;i++)
for(int j=;j<=v;j++)
if(i!=kk&&kk!=j&&dis[i][j]>dis[i][kk]+dis[kk][j])
dis[i][j]=dis[i][kk]+dis[kk][j];
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
f[i][j][]=f[i][j][]=0x3f3f3f3f;
f[][][]=f[][][]=f[][][]=;
for(int i=;i<=n;i++){
f[i][][]=f[i-][][]+dis[c[i-]][c[i]];
for(int j=;j<=i;j++){
f[i][j][]=min(f[i-][j][]+dis[c[i-]][c[i]],f[i-][j][]+(-k[i-])*dis[c[i-]][c[i]]+k[i-]*dis[d[i-]][c[i]]);
f[i][j][]=min(f[i-][j-][]+dis[c[i-]][c[i]]*(-k[i])+k[i]*dis[c[i-]][d[i]],f[i-][j-][]+dis[d[i-]][d[i]]*k[i-]*k[i]+dis[c[i-]][d[i]]*(-k[i-])*k[i]+dis[d[i-]][c[i]]*k[i-]*(-k[i])+dis[c[i-]][c[i]]*(-k[i-])*(-k[i]));
}
}
for(int i=;i<=m;i++)
ans=min(ans,min(f[n][i][],f[n][i][]));
printf("%.2lf",ans);
}

洛谷 P1850 换教室的更多相关文章

  1. 洛谷 P1850 换教室 解题报告

    P1850 换教室 题目描述 对于刚上大学的牛牛来说,他面临的第一个问题是如何根据实际情况申请合适的课程. 在可以选择的课程中,有\(2n\)节课程安排在\(n\)个时间段上.在第\(i(1≤i≤n) ...

  2. 洛谷——P1850 换教室

    P1850 换教室 有 2n 节课程安排在 nn 个时间段上.在第 i个时间段上,两节内容相同的课程同时在不同的地点进行,其中,牛牛预先被安排在教室 $c_i$​ 上课,而另一节课程在教室 $d_i$ ...

  3. 洛谷P1850换教室

    题目传送门 理解题意:给定你一个学期的课程和教室数量以及教室之间的距离还有换教室成功的概率,求一个学期走的距离的期望最小值 题目是有够恶心的,属于那种一看就让人不想刷的题目...很明显的动规,但是那个 ...

  4. 洛谷P1850 换教室

    令人印象深刻的状态转移方程... f[i][j][0/1]表示前i个换j次,第i次是否申请时的期望. 注意可能有重边,自环. 转移要分类讨论,距离是上/这次成功/失败的概率乘相应的路程. 从上次的0/ ...

  5. 洛谷P1850 换教室(概率dp)

    传送门 我的floyd竟然写错了?今年NOIP怕不是要爆零了? 这就是一个概率dp 我们用$dp[i][j][k]$表示在第$i$个时间段,已经申请了$j$次,$k$表示本次换或不换,然后直接暴力转移 ...

  6. 洛谷P1850 换教室 [noip2016] 期望dp

    正解:期望dp 解题报告: 哇我发现我期望这块真的布星,可能在刷了点儿NOIp之后会去搞一波期望dp的题...感觉连基础都没有打扎实?基础概念都布星! 好那先把这题理顺了嗷qwq 首先我们看到期望就会 ...

  7. 洛谷P1850 换教室_数学期望_Floyd

    调了一下午QAQ-让我对数学期望的理解又提升了一个层次. 首先,我们发现 v<=300v<=300v<=300 , 这样我们就可以用 FloydFloydFloyd 算法来 O(n3 ...

  8. bzoj4720 / P1850 换教室(Floyd+期望dp)

    P1850 换教室 先用Floyd把最短路处理一遍,接下来就是重头戏了 用 f [ i ][ j ][ 0/1 ] 表示在第 i 个时间段,发出了 j 次申请(注意不一定成功),并且在这个时间段是否( ...

  9. P1850 换教室

    P1850 换教室 现在有一张图, 有 \(v <= 300\) 个节点 你需要从 \(c_{1}\) 到 \(c_{2}\) 到 \(c_{n} (n <= 2000)\) 现在你有 \ ...

随机推荐

  1. TIME定时器

    一.定时器分类 STM32F1 系列中,除了互联型的产品,共有 8 个定时器,分为基本定时器,通用定时器和高级定时器.基本定时器 TIM6 和 TIM7 是一个 16 位的只能向上计数的定时器,只能定 ...

  2. MyBatis学习总结(17)——Mybatis分页插件PageHelper

    如果你也在用Mybatis,建议尝试该分页插件,这一定是最方便使用的分页插件. 分页插件支持任何复杂的单表.多表分页,部分特殊情况请看重要提示. 想要使用分页插件?请看如何使用分页插件. 物理分页 该 ...

  3. CodeForces 363B Fence

    Fence Time Limit: 1000ms Memory Limit: 262144KB This problem will be judged on CodeForces. Original ...

  4. 三种记录 MySQL 所执行过的 SQL 语句的方法

    程式 Debug 有時後從前面第一行追起來很辛苦(程式碼太多或 compile 過), 另一種做法就是從後面追起來, 反正最後寫入的是 DB, 那就從 DB 開始往前推, 所以就是要抓程式是執行哪些 ...

  5. QThread 爬坑之旅(三种办法解决QObject: Cannot create children for a parent that is in a different thread)

    Cannot create children for a parent that is in a different thread. 在Qt的官方文档,大家知道有两种方式使用QThread. You ...

  6. xml Data Type Methods in sql server

    nodes() Method (xml Data Type) https://docs.microsoft.com/en-us/sql/t-sql/xml/nodes-method-xml-data- ...

  7. html&css基础笔记

    有道笔记:http://note.youdao.com/noteshare?id=a6d7eab195085655bbfce86665524e35 一 HTML结构标签 HTML基本标签 标题标签 & ...

  8. 124.C++输出小结

    #include <iostream> #include <iomanip> using namespace std; void main() { ////调用cout的成员函 ...

  9. WebAssembly学习(四):AssemblyScript - 结构体系与内置函数

    一.结构体系 1.编译 编译器的结构相对保守. 提供源文件,其文本被标记化并解析为抽象语法树. 这里执行语法级检查. 一旦解析了所有引用的源文件,就构造一个程序并从AST初始化. 在这里进行合理性检查 ...

  10. from disk cache 与 from memory cache

    webkit资源的分类 webkit的资源分类主要分为两大类:主资源和派生资 http状态码 200 from memory cache 不访问服务器,直接读缓存,从内存中读取缓存.此时的数据时缓存到 ...