概率期望dp
期望:(百度百科)
需要注意的是,期望值并不一定等同于常识中的“期望”——“期望值”也许与每一个结果都不相等。(换句话说,期望值是该变量输出值的
平均数。期望值并不一定包含于变量的输出值集合里。)
例如:某城市有10万个家庭,没有孩子的家庭有1000个,有一个孩子的家庭有9万个,有两个孩子的家庭有6000个,有3个孩子的家庭有3000个。
则此城市中任一个家庭中孩子的数目是一个随机变量,记为X。它可取值0,1,2,3。
其中取0的概率为0.01取1的概率为0.9,取2的概率为0.06,取3的概率为0.03。
它的数学期望0×0.01+1×0.9+2×0.06+3×0.03等于1.11,即此城市一个家庭平均有小孩1.11个。
用数学式子表示为E(X)=1.11。
题意中已经给出所有的申请是相互独立事件。本题是一个概率dp:学习资源,洛谷题解。
a[],b[],c[]分别代表原教室,换后的教室,和概率
用f[i][j][0]代表前i个时间段提出了j个申请,而当前第i个没有提出申请,
f[i][j][1]代表前i个 时间段提出了j个申请,而当前第i个也提出申请,
f[i][j][1]代表前i个 时间段提出了j个申请,而当前第i个也提出申请,
f[i][j][0],可能的状态来源:(1)f[i-1][j][0],那么当前需要增加体力:p(ai,ai-1)
(2)f[i-1][j][1] 那么i-1有两种状态:通过在bi-1,概率c[i-1]*p(ai,bi-1)
未通过,在ai-1,概率(1-c[i-1])*p(ai,ai-1)
(2)f[i-1][j][1] 那么i-1有两种状态:通过在bi-1,概率c[i-1]*p(ai,bi-1)
未通过,在ai-1,概率(1-c[i-1])*p(ai,ai-1)
f[i][j][1],可能的状态来源:(1)f[i-1][j-1][0],那么i有两种状态:通过在bi,概率c[i]*p(bi,ai-1)
未通过,在ai,概率(1-c[i])*p(ai,ai-1)
(2)f[i-1][j-1][1] 那么i-1有4种状态:都通过在bi,bi-1,概率c[i]*c[i-1];
i通过,i-1未通过,bi,ai-1
i未通过,i-1通过 ai,bi-1;
都未通过,ai,ai-1.
未通过,在ai,概率(1-c[i])*p(ai,ai-1)
(2)f[i-1][j-1][1] 那么i-1有4种状态:都通过在bi,bi-1,概率c[i]*c[i-1];
i通过,i-1未通过,bi,ai-1
i未通过,i-1通过 ai,bi-1;
都未通过,ai,ai-1.
注意初始化,f[i][0[0]直接前缀和。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 2010, V = 310;
int a[N], b[N];
double d[V][V];
double c[N];
double f[N][N][2];
int cnt = 0;
int n, m, v, e;
void init()
{
for (int i=0; i<V; i++)
for (int j=0; j<V; j++)
if (i == j) d[i][j] = 0;
else d[i][j] = 1e9;
for (int i=0; i<N; i++)
for (int j=0; j<N; j++)
f[i][j][0] = f[i][j][1] = 1e9;
f[1][0][0] = 0; f[1][1][1] = 0;
}
void floyd()
{
for (int k=1; k<=v; k++)
for (int i=1; i<=v; i++)
for (int j=1; j<=v; j++)
if (d[i][k] + d[k][j] < d[i][j])
d[i][j] = d[i][k] + d[k][j];
}
int main()
{
scanf("%d%d%d%d", &n, &m, &v, &e);
for (int i=1; i<=n; i++) scanf("%d", &a[i]);
for (int i=1; i<=n; i++) scanf("%d", &b[i]);
for (int i=1; i<=n; i++) scanf("%lf", &c[i]);
init();
for (int i=1; i<=e; i++)
{
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
if (x == y) continue;
if (z < d[x][y]) d[x][y] = z;
d[y][x] = d[x][y]; //注意题目里说的会有重边的问题。
}
floyd();
for (int i=2; i<=n; i++)
{
f[i][0][0] = f[i-1][0][0] + d[a[i-1]][a[i]];
for (int j=1; j<=min(m, i); j++)
{// 第i个未申请 第i1个未申请 , 第i-1个申请,可能通未过 可能通 过
f[i][j][0] = min(f[i-1][j][0] + d[a[i-1]][a[i]], f[i-1][j][1] + d[a[i-1]][a[i]] * (1.0-c[i-1]) + d[b[i-1]][a[i]] * c[i-1]);
// 第i个申请了 第i-1个未申请 当前申请未通过 通过
f[i][j][1] = f[i-1][j-1][0] + d[a[i-1]][a[i]] * (1.0-c[i]) + d[a[i-1]][b[i]] * c[i];
//第i-1个申请了 两个申请都未通过
double t = f[i-1][j-1][1] + d[a[i-1]][a[i]] * (1.0-c[i-1]) * (1.0-c[i]);
// 第i-1个通过,i个未通过
t += d[b[i-1]][a[i]] * c[i-1] * (1.0-c[i]);
// 第i-1个未通过,i个通过
t += d[a[i-1]][b[i]] * (1.0-c[i-1]) * c[i];
//两个申请都通过啦
t += d[b[i-1]][b[i]] * c[i-1] * c[i];
f[i][j][1] = min(f[i][j][1], t); //式子太长分开写。
}
}
double ans = f[n][0][0];
for (int i=1; i<=m; i++)
{
ans = min(ans, min(f[n][i][0], f[n][i][1]));
}
printf("%.2lf", ans);
return 0;
}