51NOD演算法馬拉松 七星劍 【dp】
阿新 • • 發佈:2019-01-23
七星劍
孔炤 (命題人)
基準時間限制:1 秒 空間限制:131072 KB 分值: 80
夾克村附近來了一個大魔王,為了保護村民們的安全,夾老爺選出勇士準備去消滅這個大魔王。為了提高勇士的戰鬥力,夾克老爺決定出資為這個勇士打造一把神兵——七星劍。要打造一把七星劍,得在劍上鑲嵌7顆魔法石,在夾克村中一共找到N種不同的魔法石,標號為1,2,3..,N,每種魔法石都有很多個,其中,第i種魔法石售價為C(i)夾克幣。打造七星劍需要將魔法石一顆一顆的煉化上去,每成功煉化一次稱為加了一顆星,但由於煉化過程十分看中機緣,所以不是每一次煉化都能成功。根據古書裡記載在加第k顆星的時候(1<=k<=7),使用不同的魔法石會有不同的成功機率,書中給出了一些統計資料,大概是說在煉化第k顆星時,用魔法石i 將有prob(k,i)的機率成功,即煉化後劍上從原有的(k-1)顆星變成k顆星,但是如果失敗不但不會多出星來還會丟失lose(k,i)顆星(0<=lose(k,i)<=k-1),當然這次使用的魔法石也會被毀壞。因為魔法石比較昂貴,夾克老爺希望儘可能少的花費夾克幣來打造七星劍。問夾克老爺打造七星劍花費的期望的最小值是多少夾克幣?(相對於昂貴的魔法石,我們忽略所有鑄劍與煉化過程的花費,只考慮花在魔法石上的費用)
解釋一下樣例:
一共有2種魔法石,每一次煉化失敗都會降為0顆星,但發現煉化過程有一種100%成功的方法,即依次使用魔法石{1,1,2,2,1,1,2}即可,總花費為10.除了這種方案,其他方案期望都比10大。
Input
一組測試資料.
第一行會有一個整數N,表示魔法石的種類有多少種,其中,1<=N<=100.
之後一行會有N個整數,第i個數表示魔法石i的價格Ci,其中1<=Ci<=10000.
之後7行記錄prob矩陣,這7行中每行N個小數,第k行的第i項表示prob(k,i)的大小,其中0<=prob(k,i)<=1,且每一項小數點後最多2位。
再之後的7行記錄了lose矩陣,這7行中每行N個小數,第k行的第i項表示lose(k,i)的大小,其中0<=lose(k,i)<=k-1。
Output
每組詢問輸出一行一個小數,表示夾克老爺的最小期望花費(絕對誤差或相對誤差在1e-8 範圍內即可,並不要求輸出多少位,只要精度對即可),如果夾克老爺永遠沒法鑄造出七星劍,那麼輸出-1.
(友情提示:程式碼需要注意精度問題)
Input示例
2
1 2
1.0 0.1
1.0 0.1
0.1 1.0
0.1 1.0
1.0 0.1
1.0 0.1
0.1 1.0
0 0
1 1
2 2
3 3
4 4
5 5
6 6
Output示例
10.00
顯然 當從i-1顆星到i顆星 ,選哪種寶石,成功率都為0時,無解
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<string>
#include<vector>
#include<deque>
#include<queue>
#include<algorithm>
#include<set>
#include<map>
#include<stack>
#include<ctime>
#include <string.h>
#include<math.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
const double EPS = 1e-8;
const int inf=1e9+7;
const int N = 100+5;
int c[N];
int prob[8][N];
int lose[8][N];
double d[8];
void dp(int n){
d[0]=0;
for(int i=1;i<=7;++i){
d[i]=1.0/0.0;
bool haveAns=false;
for(int j=1;j<=n;++j){
if(prob[i][j]==0){
continue;
}
haveAns=true;
double ans=d[i-1]*100+c[j]-(100-prob[i][j])*d[i-1-lose[i][j]];
ans/=prob[i][j];
d[i]=min(d[i],ans);
}
if(!haveAns){
puts("-1");
return;
}
}
printf("%.8f\n", d[7]);
}
int main()
{
//freopen("/home/lu/Documents/r.txt","r",stdin);
int n;
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%d",c+i);
c[i]*=100;
}
for(int i=1;i<=7;++i){
for(int j=1;j<=n;++j){
double tmp;
scanf("%lf",&tmp);
prob[i][j]=100*(tmp+EPS);
}
}
for(int i=1;i<=7;++i){
for(int j=1;j<=n;++j){
double tmp;
scanf("%lf",&tmp);
lose[i][j]=tmp+EPS;
//scanf("%d",&lose[i][j]);
}
}
dp(n);
return 0;
}