P1850 [NOIP 2016 提高组] 换教室
简要题意
给你一张图,给你几个点,要求你按顺序以最短路径 走完所有点。你有 \(m\) 次机会将其中的点换成另一个点(换的点是给定的), 你有 \(p_i\) 的概率成功,求最优策略下的路径长度总和的最小期望值。
前置知识
概率与期望(了解即可),最短路,dp
思路
首先因为我们需要走最短路所以我们提前将最短路处理出来,方便转移。
接着对于期望题吗,我们开始考虑dp做法。设出状态 \(dp_{i,j}\) 表示走到第 \(i\) 个点用了 \(j\) 次机会的期望值(显然要记录走到第几个点以及用了几次)然后我们发现我们无法转移,因为期望增加的是路径长度但是现在我们不知道在什么点以及去什么点所以不好做。
那我们在加一位,将状态设为 \(dp_{i,j,0/1}\) 最后的 \(0/1\) 表示当前点是否要换,这要我们只需要分类讨论一下即可。
代码
#include <bits/stdc++.h>
using namespace std;
const int N=2e3+10;
const double inf=1e17+10;
int n,m,v,e,c[N],d[N],mp[N][N];
double k[N],dp[N][N][2];
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>m>>v>>e;
for(int i=1;i<=n;i++)cin>>c[i];
for(int i=1;i<=n;i++)cin>>d[i];
for(int i=1;i<=n;i++)cin>>k[i];
memset(mp,0x3f,sizeof(mp));
for(int i=1;i<=e;i++)
{
int x,y,z;cin>>x>>y>>z;
mp[x][y]=mp[y][x]=min(mp[x][y],z);
}
for(int kk=1;kk<=v;kk++)
for(int i=1;i<=v;i++)
for(int j=1;j<=v;j++)
mp[i][j]=min(mp[i][j],mp[i][kk]+mp[kk][j]);//预处理出最短路
for (int i=1;i<=v;i++)mp[i][i]=mp[i][0]=mp[0][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][0][0]=dp[1][1][1]=0;//初始化,第一次换或不换期望都是0
for(int i=2;i<=n;i++)
{
dp[i][0][0]=dp[i-1][0][0]+mp[c[i-1]][c[i]];
for(int j=1;j<=min(m,i);j++)
{
dp[i][j][0]=min(dp[i][j][0],min(dp[i-1][j][0]+mp[c[i-1]][c[i]],dp[i-1][j][1]+mp[c[i-1]][c[i]]*(1-k[i-1])+mp[d[i-1]][c[i]]*k[i-1]));//当前点不申请
dp[i][j][1]=min(dp[i][j][1],min(dp[i-1][j-1][0]+mp[c[i-1]][c[i]]*(1-k[i])+mp[c[i-1]][d[i]]*k[i],dp[i-1][j-1][1]+mp[c[i-1]][c[i]]*(1-k[i-1])*(1-k[i])+mp[d[i-1]][c[i]]*k[i-1]*(1-k[i])+mp[c[i-1]][d[i]]*(1-k[i-1])*k[i]+mp[d[i-1]][d[i]]*k[i-1]*k[i]));//当前点申请
// cout<<i<<' '<<j<<' '<<dp[i][j][0]<<" "<<dp[i][j][1]<<'\n';
}
}
double ans=inf;
for(int i=0;i<=m;i++)ans=min(ans,min(dp[n][i][0],dp[n][i][1]));
cout<<fixed<<setprecision(2)<<ans<<'\n';
return 0;
}
理解
我们发现对于期望的 \(dp\) 可以理解为多项式,我们维护期望就是维护了期望的定义式的那个多项式。
思考
- 如果没有不能根据结果统计答案?感觉比较像ABC402E Payment Required
- 如果可以将换的教室任意选择?感觉不好做没什么性质

浙公网安备 33010602011771号