小周猪猪
2020-09-21 19:02:44
搞了一天的期望神题
我们设
有一些显然但很重要的结论,就是:
对于结论2:当
因此我们便有了算法的大致思路:每一次都寻找一个期望值最小的点,并固定这个点的期望值;同时也用这个点的期望值去更新未被更新的期望值。
该算法的思路与Dijkstra算法类似。
考虑如何转移:我们发现若我们要转移节点
观察到我们此时计算的
因此我们的期望天数就变成了
则上述转移方程就变成了:
然后就可以愉快的转移辣
#include <bits/stdc++.h>
using namespace std;
const int N = 2000;
int n;
int vis[N];
double s[N], P[N][N], E[N];
int read(void)
{
int s = 0, w = 0; char c = getchar();
while (!isdigit(c)) w |= c == '-', c = getchar();
while (isdigit(c)) s = s*10+c-48, c = getchar();
return w ? -s : s;
}
int main(void)
{
n = read();
for(int i=1;i<=n;++i)
for (int j=1;j<=n;++j)
P[i][j] = 1.0 * read() / 100.0;
if (n == 1) return puts("0"), 0;
vis[n] = 1, E[n] = 0;
for (int i=1;i<=n;++i) {
E[i] = 1;
s[i] = 1 - P[i][n];
}
for (int i=1;i<=n;++i)
{
int p = 0;
double Min = 1e18;
for (int j=1;j<=n;++j)
if (vis[j] == 0 && 1.0 * E[j] / (1 - s[j]) < Min)
Min = 1.0 * E[j] / (1 - s[j]), p = j;
vis[p] = 1;
if (p == 1) return printf("%.15lf\n", Min) * 0;
for (int j=1;j<=n;++j)
E[j] += 1.0 * E[p] / (1 - s[p]) * P[j][p] * s[j], s[j] *= 1.0 - P[j][p];
}
return 0;
}