●51NOD 1705 七星劍

*ZJ發表於2018-03-11

題鏈:

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;
}

 

  

 

相關文章