题意:
七颗星,第$i$课星用第$j$个宝石有$p[i][j]$的概率成功,失败将为$g[i][j]$颗星;
第$j$个宝石化费$c[j]$
求最小期望化费
$MD$本来自己思路挺对的看了半天题解还不知道他的高斯消元是什么意思....
本题逆推并不好,(真的需要高斯消元),正推比较好
$f[i]$表示有$i$颗星的期望化费
$f[i]=min{f[i-1]+c_j+(1-p_{i,j})*(f[i]-f[g_{i,j}]) }$
减法成立是因为期望的线性性质
变形一下直接$DP$就好了
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; typedef long long ll; const int N=105; const double eps=1e-9,INF=1e100; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } int n,c[N],sum,g[10][N]; double p[10][N]; double d[10],x; void dp(){ d[0]=0; for(int i=1;i<=7;i++){ d[i]=INF; for(int j=1;j<=n;j++) if(p[i][j]){ double _=d[i-1]+c[j]-(1-p[i][j])*d[g[i][j]]; d[i]=min(d[i],_/p[i][j]); } } printf("%.10lf",d[7]); } int main(){ // freopen("in","r",stdin); n=read(); for(int i=1;i<=n;i++) c[i]=read(); for(int i=1;i<=7;i++){ bool flag=0; for(int j=1;j<=n;j++) scanf("%lf",&p[i][j]),flag|=( abs(p[i][j])>eps ); if(!flag) {puts("-1");return 0;} } for(int i=1;i<=7;i++) for(int j=1;j<=n;j++) g[i][j]=i-1-read(); dp(); }