研读数据,我们发现,28分是可以轻松拿到的:
对于的一个点,直接即可。
其余的标紫色的数据点,跑一遍最短路,依次相加各个教室之间的最短路径长度即可。
其实,↑ 也是建立在你知道期望是啥的基础上的。
对于本体题解,请见落谷题解:https://www.luogu.org/problemnew/solution/P1850
期望这个东西,本蒟蒻还是没有理解它的线性....
有一句话我觉得总结的挺好的:
期望的计算:如果概率为k的代价为w1,概率为(1-k)的代价为w2,那么期望就是概率乘代价,即 kw1+(1-k)w2
对于概率不止两个的,但是各个概率加起来和为1的情况同样适用
期望DP的套路:n个阶段的期望等于每个阶段的期望之和,显然的. 其实,我觉得不是很显然的。。。
总结:
一般的期望DP有成功和失败两种,在阶段进行转移时,当前阶段的失败和成功和上一阶段的成功和失败有关系时,要分开讨论,即分开计算概率再乘以分别的代价。
这道题大概是最简单的期望DP了吧-_-
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define V 305
#define N 2004
#define inf 1e7
#define inf_z 0x3f3f3f3f
using namespace std;
inline int wread(){
char c=getchar ();int flag=1,wans=0;
while (c<'0'||c>'9'){if (c=='-') flag=-1;c=getchar ();}
while (c>='0'&&c<='9'){wans=wans*10+c-'0';c=getchar ();}
return wans*=flag;
}
int n,m,v,e;
int sav[V][V]; //两点之间的距离
int a[N],b[N];// a:一开始所在的教室 b:可以申请到的教室
int dis[V][V]; //两点之间的最短距离
double P[N];//教室更换成功的概率
bool abl2=true;
double dp[2][N][N];
int main (){
//细节问题:输出小数后两位!!!
n=wread();m=wread();v=wread();e=wread();
//4pts
if (n==1){
puts("0.00");return 0;
}
memset (sav,inf_z,sizeof sav);
for (int i=1;i<=n;++i)
a[i]=wread();
for (int i=1;i<=n;++i)
b[i]=wread();
for (int i=1;i<=n;++i){
scanf ("%lf",&P[i]);
if (P[i]!=1.000) abl2=false;
}
for (int i=1;i<=e;++i){
int q=wread(),z=wread(),w=wread();
if (q==z) {sav[q][z]=0;continue;}
sav[q][z]=min (sav[q][z],w);
sav[z][q]=sav[q][z];
}
//Floyed
for (int k=1;k<=v;++k){
for (int i=1;i<=v;++i){
for (int j=1;j<=v;++j){
if (i==j) sav[i][j]=0;
if (sav[i][j] > sav[i][k] + sav[k][j])
sav[i][j] = sav[i][k] + sav[k][j],sav[j][i]=sav[i][j];
}
}
}
//24pts
if (m==0){
double ans=0;
for (int i=2;i<=n;++i){
ans+=(double)sav[a[i-1]][a[i]];
}
printf("%.2lf\n",(double)ans);
}
else {
//手动memset
for (int i=1;i<=n;++i)
for (int k=0;k<=m;++k)
dp[0][i][k]=dp[1][i][k]=inf;
dp[0][1][0]=0.0;
if (m>=1) dp[1][1][1]=0.0;
for (int i=2;i<=n;++i){//当前在第i间教室
//0
dp[0][i][0] = dp[0][i-1][0] + (double)sav[a[i-1]][a[i]];
for (int k=1;k<=min (m,i) ;++k){//换了k次教室
dp[0][i][k]= min (dp[0][i-1][k]+(double)sav[a[i-1]][a[i]],dp[1][i-1][k]+P[i-1]*(double)sav[b[i-1]][a[i]]+(1.0-P[i-1])*(double)sav[a[i-1]][a[i]]);
dp[1][i][k]= min (dp[0][i-1][k-1]+P[i]*(double)sav[a[i-1]][b[i]]+(1.0-P[i])*(double)sav[a[i-1]][a[i]], dp[1][i-1][k-1]+ P[i-1]*P[i]*(double)sav[b[i-1]][b[i]] + P[i-1]*(1-P[i])*(double)sav[b[i-1]][a[i]] + (1-P[i-1])*P[i]*(double)sav[a[i-1]][b[i]] + (1-P[i-1])*(1-P[i])*(double)sav[a[i-1]][a[i]] ) ;
}
}
double ans=inf;
for (int k=0;k<=m;++k)
ans = min (ans, min (dp[0][n][k],dp[1][n][k]));
printf("%.2lf\n",ans);
}
return 0;
}