bzoj3029 守卫者的挑战 (多维dp)

题面:

  打开了黑魔法师Vani的大门,队员们在迷宫般的路上漫无目的地搜寻着关押applepi的监狱的所在地。突然,眼前一道亮光闪过。“我,Nizem,是黑魔法圣殿的守卫者。如果你能通过我的挑战,那么你可以带走黑魔法圣殿的地图……”瞬间,队员们被传送到了一个擂台上,最初身边有一个容量为K的包包。

  擂台赛一共有N项挑战,各项挑战依次进行。第i项挑战有一个属性ai,如果ai>=0,表示这次挑战成功后可以再获得一个容量为ai的包包;如果ai=-1,则表示这次挑战成功后可以得到一个大小为1 的地图残片。地图残片必须装在包包里才能带出擂台,包包没有必要全部装满,但是队员们必须把获得的所有的地图残片都带走(没有得到的不用考虑,只需要完成所有N项挑战后背包容量足够容纳地图残片即可),才能拼出完整的地图。并且他们至少要挑战成功L次才能离开擂台。
  队员们一筹莫展之时,善良的守卫者Nizem帮忙预估出了每项挑战成功的概率,其中第i项挑战成功的概率为pi%。现在,请你帮忙预测一下,队员们能够带上他们获得的地图残片离开擂台的概率。

Input:

第一行三个整数N,L,K。

第二行N个实数,第i个实数pi表示第i项挑战成功的百分比。

第三行N个整数,第i个整数ai表示第i项挑战的属性值.

Output:

一个整数,表示所求概率,四舍五入保留6 位小数。

solution:

比较明显的动态规划。F[i][j][k]表示经过前 i 项挑战,目前背包容量为 j,有 k 项挑战获得了胜利的概率。

我们可以定义200为0,j>200 代表背包有 j-200 的剩余空间, j<200 代表目前有 200-j 的地图残片还未装入。
j 的取值范围是0~400,超出范围没有意义,直接与 400 取 Min/Max 即可。转移方式只有两种:第 i 次挑战成功/失败.

同时,我们的背包空间大于200,也是没意义的,直接与 400 取 Min/Max 即可。

综上:时间复杂度 O(400*n^2)。

code:

#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>

#define ll long long
#define db double
#define inf 0x7fffffff
#define rg register int

using namespace std;

int n,m,t;
int a[205];
db ans,su;
db b[205];
db c[205];
db f[205][405][205];

inline int qr(){
	char ch; int sign=1;
	while((ch=getchar())<'0'||ch>'9')
	    if(ch=='-')sign=-1;
	int res=ch^48;
	while((ch=getchar())>='0'&&ch<='9')
		res=res*10+(ch^48);
	return res*sign;
}

int main(){
	//freopen("guard.in","r",stdin);
	//freopen("guard.out","w",stdout);
	n=qr(),t=qr(),m=qr();
	for(rg i=1;i<=n;++i)
		c[i]=(db)1-(b[i]=(db)qr()/(db)100);
	for(rg i=1;i<=n;++i)a[i]=qr();
	if(m>200)m=200;
	f[1][m+200][0]=1;
	for(rg k=1;k<=n;++k){
		for(rg i=1;i<=400;++i){
			for(rg j=0;j<200;++j){
				if(f[k][i][j]==0)continue;
				f[k+1][i][j]+=f[k][i][j]*c[k];
				su=f[k][i][j]*b[k];
				if(a[k]>=0){
					if(i+a[k]>400)f[k+1][400][j+1]+=su;
					else f[k+1][i+a[k]][j+1]+=su;
				}else{
					f[k+1][i-1][j+1]+=su;
				}
			}
		}
	}++n;
	for(rg i=200;i<=400;++i)
		for(rg j=t;j<=200;++j)
			ans+=f[n][i][j];
	printf("%.6lf",ans);
	return 0;
}

posted @ 2019-01-25 22:29  一只不咕鸟  阅读(270)  评论(0编辑  收藏  举报