CODEVS 1997 守衛者的挑戰(三維dp)

畫船聽雨發表於2014-11-10

題目很簡單,就是一個三維的dp,狀態轉移方程很好想出來,有一點需要注意這道題目在取的中間過程的時候允許出現揹包裝不下的情況,只要最後的狀態是可以的就行了.注意負數的轉移就行了啊.

maxn = 210 MLE, 201就AC了啊。


題目描述 Description

  開啟了黑魔法師Vani的大門,隊員們在迷宮般的路上漫無目的地搜尋著關押applepi的監獄的所在地。突然,眼前一道亮光閃過。“我,Nizem,是黑魔法聖殿的守衛者。如果你能通過我的挑戰,那麼你可以帶走黑魔法聖殿的地圖……”瞬間,隊員們被傳送到了一個擂臺上,最初身邊有一個容量為K的包包。
  擂臺賽一共有項挑戰,各項挑戰依次進行。第項挑戰有一個屬性ai,如果ai≥0,表示這次挑戰成功後可以再獲得一個容量為ai的包包;如果ai = -1,則表示這次挑戰成功後可以得到一個大小為 1 的地圖殘片。地圖殘片必須裝在包包裡才能帶出擂臺,包包沒有必要全部裝滿,但是隊員們必須把獲得的所有的地圖殘片都帶走(沒有得到的不用考慮,只需要完成所有N項挑戰後揹包容量足夠容納地圖殘片即可),才能拼出完整的地圖。並且他們至少要挑戰成功L次才能離開擂臺。
  隊員們一籌莫展之時,善良的守衛者Nizem幫忙預估出了每項挑戰成功的概率,其中第i項挑戰成功的概率為pi %。現在,請你幫忙預測一下,隊員們能夠帶上他們獲得的地圖殘片離開擂臺的概率。

輸入描述 Input Description

  第一行三個整數N,L,K。
  第二行N個實數,第i個實數pi表示第i項挑戰成功的百分比。
  第三行N個整數,第i個整數ai表示第i項挑戰的屬性值。

輸出描述 Output Description

  一個整數,表示所求概率,強制四捨五入保留6位小數。

樣例輸入 Sample Input

【樣例輸入1】
3 1 0
10 20 30
-1 -1 2

【樣例輸入2】
5 1 2
36 44 13 83 63
-1 2 -1 2 1

樣例輸出 Sample Output

【樣例輸出1】
0.300000

【樣例輸出2】
0.980387

資料範圍及提示 Data Size & Hint

  在第一個樣例中,若第三項挑戰成功,如果前兩場中某場勝利,隊員們就有空間來容納得到的地圖殘片,如果挑戰失敗,根本就沒有獲得地圖殘片,不用考慮是否能裝下;若第三項挑戰失敗,如果前兩場有勝利,沒有包來裝地圖殘片,如果前兩場都失敗,不滿足至少挑戰成功L次(L = 1)的要求。因此所求概率就是第三場挑戰獲勝的概率。

  對於 100% 的資料,保證0≤K≤2000,0≤N≤200,-1≤ai≤1000,0≤L≤N,0≤pi≤100。

來源:Nescafe 17

#include <algorithm>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <iomanip>
#include <stdio.h>
#include <string>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <set>
#define eps 1e-8
#define M 1000100
#define LL long long
//#define LL long long
#define INF 0x3f3f3f
#define PI 3.1415926535898
#define mod 1000000007


const int maxn = 201;

using namespace std;

double dp[maxn][2*maxn][maxn];
struct node
{
    int vi;
    double p;
} f[maxn];

int main()
{
    int n, m, k;
    while(~scanf("%d %d %d",&n, &m, &k))
    {
        double x;
        for(int i = 1; i <= n; i++)
        {
            scanf("%lf",&x);
            x /= 100.0;
            f[i].p = x;
        }
        for(int i = 1; i <= n; i++) scanf("%d",&f[i].vi);
        memset(dp, 0, sizeof(dp));
        dp[0][k+200][0] = 1.0;
        for(int i = 1; i <= n; i++)
        {
            for(int j = 1; j <= 401; j++)
            {
                for(int p = 0; p <= i-1; p++)
                {
                    dp[i][j][p] += dp[i-1][j][p]*(1.0-f[i].p);
                    int xs = f[i].vi;
                    dp[i][j+xs][p+1] += dp[i-1][j][p]*f[i].p;
                }
            }
        }
        double sum = 0;
        for(int i = 200; i <= 401; i++)
            for(int j = m; j <= n; j++) sum += dp[n][i][j];
        printf("%.6lf\n",sum);
    }
    return 0;
}


相關文章