1. 程式人生 > >51NOD演算法馬拉松 七星劍 【dp】

51NOD演算法馬拉松 七星劍 【dp】

七星劍
孔炤 (命題人)
基準時間限制: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

d[i]=i
jj
d[i]=min(d[i1]+C[j]+(1prob[i][j])(d[i]d[i1lose[i][j]]))
> d[i]=min((d[i1]+C[j](1prob[i][j])d[i1lose[i][j]])/(prob[i][j]))

顯然 當從i-1顆星到i顆星 ,選哪種寶石,成功率都為0時,無解
O(n)

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