题目:luogu1850.
题目大意:给定
v
v
v个教室,教室之间有
e
e
e条无向边边,保证连通.现在有
n
n
n组教室,每组有一个被钦定的教室和一个可以替换的教室,现在给你
m
m
m次替换教室的机会,以及当你打算替换掉一组教室时成功的概率,让你求最后依次经过你选择的教室的期望路径最小值.
1
≤
v
≤
300
,
1
≤
n
,
m
≤
2000
1\leq v\leq 300,1\leq n,m\leq 2000
1≤v≤300,1≤n,m≤2000.
我觉得我的题目大意好像解释得不是很清晰…
模拟赛考真题的时候由于我没有写过概率DP,然后一直调这道题调了3h,T2部分分一点都没拿…
现在突然发现自己列的状态貌似不太主流,然后写的方式又细节极多,而且还是在我迷了很久期望的定义的情况写的…
我们现在来详解这道题.
首先我在考场列的状态是 f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]表示到第 i i i个时段,用掉了 j j j次机会,是否成功换掉了第 j j j组教室的期望.
这个状态实际上是错误的,因为这个状态它已知是否申请成功,而题目上说是一次性提交的,说明不知道是否申请成功.
然后我们会发现这个东西列出方程后细节比较多,我们换一种转态.
我们依然设状态 f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k],但这是 k k k表示的是否申请去换第 j j j组教室.
那么容易列出方程,不过方程太长这里就不列出了.
当 i = j = 0 i=j=0 i=j=0时是要特殊处理的, j > 0 j>0 j>0时 f [ i ] [ j ] [ 1 ] f[i][j][1] f[i][j][1]时没有意义的,所以要判断.
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=2000,V=300,INF=1<<29;
int dis[V+9][V+9];
int c[N+9],d[N+9];
double k[N+9],f[N+9][N+9][2],ans=INF*1.0;
int n,m,v,e;
void floyd(){
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]);
}
Abigail into(){
scanf("%d%d%d%d",&n,&m,&v,&e);
for (int i=1;i<=n;i++) scanf("%d",&c[i]);
for (int i=1;i<=n;i++) scanf("%d",&d[i]);
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++)
if (i^j) dis[i][j]=INF;
int x,y,z;
for (int i=1;i<=e;i++){
scanf("%d%d%d",&x,&y,&z);
if (dis[x][y]<=z) continue;
dis[x][y]=dis[y][x]=z;
}
}
Abigail work(){
floyd();
for (int i=0;i<=n;i++)
for (int j=0;j<=m;j++)
f[i][j][0]=f[i][j][1]=INF*1.0;
f[1][0][0]=0;f[1][1][1]=0;
for (int i=2;i<=n;i++){
f[i][0][0]=f[i-1][0][0]+dis[c[i-1]][c[i]];
for (int j=1;j<=m;j++){
f[i][j][0]=min(f[i][j][0],f[i-1][j][0]+dis[c[i-1]][c[i]]);
f[i][j][0]=min(f[i][j][0],f[i-1][j][1]+dis[c[i-1]][c[i]]*(1-k[i-1])+dis[d[i-1]][c[i]]*k[i-1]);
if (j>0) f[i][j][1]=min(f[i][j][1],f[i-1][j-1][0]+dis[c[i-1]][c[i]]*(1-k[i])+dis[c[i-1]][d[i]]*k[i]);
if (j>0) f[i][j][1]=min(f[i][j][1],f[i-1][j-1][1]+dis[c[i-1]][c[i]]*(1-k[i-1])*(1-k[i])+dis[c[i-1]][d[i]]*(1-k[i-1])*k[i]+dis[d[i-1]][c[i]]*k[i-1]*(1-k[i])+dis[d[i-1]][d[i]]*k[i-1]*k[i]);
}
}
for (int i=0;i<=m;i++)
ans=min(ans,min(f[n][i][0],f[n][i][1]));
}
Abigail outo(){
printf("%.2lf\n",ans);
}
int main(){
into();
work();
outo();
return 0;
}