題鏈:
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1705
題解:
期望dp,期望的線性性質
(首先對於第k顆星,一定只會用同一種膜法石去煉化它。)
定義f[k]表示煉化成功第k顆星最小的期望花費。
正向列舉k,然後列舉當前用哪個膜法石i去煉化
當然要為兩種情況:煉化成功與否
1.成功:期望的花費即為prob[k][i]*c[i]
2.失敗:
首先也有一個c[i]的花費(雖然沒有成功,但是還是用了這個膜法石),
令j=k-lose[k][i],用拿i膜法石成功煉化第k顆星的期望花費為_f;
然後我們回到之前的某個狀態:成功煉化了j-1顆星,
也就是說,我們如果要煉化成功第k顆星,我們還需要重新成功煉化第j~k這些星。
設重新成功煉化那1mol的星,期望需要w的花費,
按照期望的線性性質可以得到:w=f[j]+f[j+1]+......+f[k-1]+_f
若統計字首和的話,即w=_f+sumf[k-1]-sumf[j-1];
所以可以得到失敗時期望花費的轉移:
(1-prob[k][i])*(c[i]+_f+sumf[k-1]-sumf[j-1])
所以綜上,拿i膜法石成功煉化第k顆星的期望花費為:
_f=prob[k][i]*c[i]+(1-prob[k][i])*(c[i]+_f+sumf[k-1]-sumf[j-1]);
上式通過移項後,可以求出_f的值。
然後對f[k]取min即可:f[k]=min(f[k],_f(每種膜法石都可以得到一個_f))。
dp結束後sumf[7]=f[1]+f[2]+...+f[7]即是答案。
(輸出-1的情況直接在讀入時特判掉就好)
程式碼:
#include<bits/stdc++.h> #define MAXN 105 #define doubleINF 1e37 using namespace std; const double eps=1e-10; int c[MAXN],lose[10][MAXN]; double prob[10][MAXN],f[10],sumf[10]; int N; int main(){ ios::sync_with_stdio(0); cin>>N; for(int i=1;i<=N;i++) cin>>c[i]; for(int k=1;k<=7;k++){ bool fg=0; for(int i=1;i<=N;i++) cin>>prob[k][i],fg|=(prob[k][i]>eps); if(!fg) return printf("-1\n"),0; } for(int k=1;k<=7;k++) for(int i=1;i<=N;i++) cin>>lose[k][i],lose[k][i]=k-lose[k][i]; for(int k=1;k<=7;k++){ f[k]=doubleINF; for(int i=1;i<=N;i++){ double P=prob[k][i]; int C=c[i],j=lose[k][i]; double _f=P*C+(1-P)*(C+sumf[k-1]-sumf[j-1]); _f=_f/P; f[k]=min(f[k],_f); } sumf[k]=sumf[k-1]+f[k]; } cout<<fixed<<setprecision(10)<<sumf[7]<<endl; return 0; }