题意:
就是给你n节课,每节课刚开始在va[i]教室,然后每节课都可以申请调换,调换到vb[i]教室,申请成功的概率是f[i]。然后再给你每个教室之间的距离,和一共申请的最多次数m。然后必须要按顺序上课,然后问你在上完n节课,走的路程的期望值最小是多少。
思考:
其实第一次做这种,要仔细思考。首先问你路程的期望值,那么如果直接求总的肯定不好求。可以分开很多段去求,对于2到n,每次都要从i-1走到i,对于每个这样的路程都求一次期望,把这些期望加起来就好了。对于有n节课,m次申请,很明显了,定义dp[i][j][0/1]为,上到第i节课,用了j次申请,当前申请或不申请,最小期望总和。那么转移的时候,分好情况就行。由于期望值是所有概率累加起来的,所以转移的时候,如果从dp[i-1][j-1][1]来转移,那么看看要加多少期望,这个期望值是好几种不同的情况累加起来的。然后再转移。这题可以定义恰好用了j次申请,也可以定义不超过j次。只是两者的初始化的时候有些地方不一样。
代码:
#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define db double
#define int long long
#define PII pair<int,int >
#define mem(a,b) memset(a,b,sizeof(a))
#define IOS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
using namespace std;
const int mod = 1e9+7,inf = 1e9;
const int N = 2e5+10,M = 2010;
int T,n,m;
int va[M];
int vb[M];
db f[M];
db dist[M][M];
db dp[M][M][2];
signed main()
{
IOS;
int v,e;
cin>>n>>m>>v>>e;
for(int i=1;i<=n;i++) cin>>va[i];
for(int i=1;i<=n;i++) cin>>vb[i];
for(int i=1;i<=n;i++) cin>>f[i];
for(int i=1;i<=v;i++)
{
for(int j=1;j<=v;j++)
if(i!=j) dist[i][j] = inf;
}
while(e--)
{
int a,b,c;
cin>>a>>b>>c;
dist[b][a] = dist[a][b] = min(dist[a][b],(db)c);
}
for(int k=1;k<=v;k++) //先把任意两点最小距离求出来
{
for(int i=1;i<=v;i++)
{
for(int j=1;j<=v;j++)
dist[i][j] = min(dist[i][j],dist[i][k]+dist[k][j]);
}
}
for(int i=1;i<=n;i++) for(int j=0;j<=m;j++) dp[i][j][0] = dp[i][j][1] = inf; //定义恰好的用了j次
dp[1][0][0] = dp[1][1][1] = 0; //初始化边界
for(int i=2;i<=n;i++)
{
for(int j=0;j<=m;j++)
{
db sum1 = dp[i-1][j][1],sum2 = dp[i-1][j][0]; //可以从这两种类型转移过来
sum1 += f[i-1]*dist[vb[i-1]][va[i]];
sum1 += (1-f[i-1])*dist[va[i-1]][va[i]]; //这一种类型就要加上所有情况的概率期望
sum2 += dist[va[i-1]][va[i]];
dp[i][j][0] = min(sum1,sum2); //取一个最小的
if(j<1) continue;
sum1 = dp[i-1][j-1][1],sum2 = dp[i-1][j-1][0]; //同理也是
sum1 += f[i-1]*f[i]*dist[vb[i-1]][vb[i]];
sum1 += (1-f[i-1])*f[i]*dist[va[i-1]][vb[i]];
sum1 += f[i-1]*(1-f[i])*dist[vb[i-1]][va[i]];
sum1 += (1-f[i-1])*(1-f[i])*dist[va[i-1]][va[i]];
sum2 += f[i]*dist[va[i-1]][vb[i]];
sum2 += (1-f[i])*dist[va[i-1]][va[i]];
dp[i][j][1] = min(sum1,sum2);
}
}
db anw = inf;
for(int i=0;i<=m;i++) anw = min(anw,min(dp[n][i][0],dp[n][i][1]));
printf("%.2lf",anw);
return 0;
}
总结:
多多思考。