守卫者的挑战
描述 Description
打开了黑魔法师Vani的大门,队员们在迷宫般的路上漫无目的地搜寻着关押applepi的监狱的所在地。突然,眼前一道亮光闪过。“我,Nizem,是黑魔法圣殿的守卫者。如果你能通过我的挑战,那么你可以带走黑魔法圣殿的地图……”瞬间,队员们被传送到了一个擂台上,最初身边有一个容量为K的包包。
擂台赛一共有N项挑战,各项挑战依次进行。第i项挑战有一个属性ai,如果ai>=0,表示这次挑战成功后可以再获得一个容量为ai的包包;如果ai=-1,则表示这次挑战成功后可以得到一个大小为1 的地图残片。地图残片必须装在包包里才能带出擂台,包包没有必要全部装满,但是队员们必须把 【获得的所有的】地图残片都带走(没有得到的不用考虑,只需要完成所有N项挑战后背包容量足够容纳地图残片即可),才能拼出完整的地图。并且他们至少要挑战成功L次才能离开擂台。
队员们一筹莫展之时,善良的守卫者Nizem帮忙预估出了每项挑战成功的概率,其中第i项挑战成功的概率为pi%。现在,请你帮忙预测一下,队员们能够带上他们获得的地图残片离开擂台的概率。
擂台赛一共有N项挑战,各项挑战依次进行。第i项挑战有一个属性ai,如果ai>=0,表示这次挑战成功后可以再获得一个容量为ai的包包;如果ai=-1,则表示这次挑战成功后可以得到一个大小为1 的地图残片。地图残片必须装在包包里才能带出擂台,包包没有必要全部装满,但是队员们必须把 【获得的所有的】地图残片都带走(没有得到的不用考虑,只需要完成所有N项挑战后背包容量足够容纳地图残片即可),才能拼出完整的地图。并且他们至少要挑战成功L次才能离开擂台。
队员们一筹莫展之时,善良的守卫者Nizem帮忙预估出了每项挑战成功的概率,其中第i项挑战成功的概率为pi%。现在,请你帮忙预测一下,队员们能够带上他们获得的地图残片离开擂台的概率。
输入格式 InputFormat
第一行三个整数N,L,K。
第二行N个实数,第i个实数pi表示第i项挑战成功的百分比。
第三行N个整数,第i个整数ai表示第i项挑战的属性值.
第二行N个实数,第i个实数pi表示第i项挑战成功的百分比。
第三行N个整数,第i个整数ai表示第i项挑战的属性值.
输出格式 OutputFormat
一个整数,表示所求概率,四舍五入保留6 位小数。
样例输入 SampleInput [复制数据]
样例输入1
3 1 0
10 20 30
-1 -1 2
样例输入2
5 1 2
36 44 13 83 63
-1 2 -1 2 1
3 1 0
10 20 30
-1 -1 2
样例输入2
5 1 2
36 44 13 83 63
-1 2 -1 2 1
样例输出 SampleOutput [复制数据]
样例输出1
0.300000
样例输出2
0.980387
0.300000
样例输出2
0.980387
数据范围和注释 Hint
若第三项挑战成功,如果前两场中某场胜利,队员们就有空间来容纳得到的地图残片,如果挑战失败,根本就没有获得地图残片,不用考虑是否能装下;若第三项挑战失败,如果前两场有胜利,没有包来装地图残片,如果前两场都失败,不满足至少挑战成功L次的要求。因此所求概率就是第三场挑战获胜的概率。
对于 100% 的数据,保证0<=K<=2000,0<=N<=200,-1<=ai<=1000,0<=L<=N,0<=pi<=100。
对于 100% 的数据,保证0<=K<=2000,0<=N<=200,-1<=ai<=1000,0<=L<=N,0<=pi<=100。
题解
比较明显的动态规划。 F[i][j][k]表示经过前 i 项挑战,目前背包容量为 j,有 k 项挑战获得了
胜利的概率。 j>0 代表背包有 j 的剩余空间, j<0 代表目前有-j 的地图残片还未装入。 j 的取值
范围是-200~200,超出范围没有意义,直接与±200 取 Min/Max 即可。
转移方式只有两种:第 i 次挑战成功/失败.
时间复杂度 O(400*n^2)。
胜利的概率。 j>0 代表背包有 j 的剩余空间, j<0 代表目前有-j 的地图残片还未装入。 j 的取值
范围是-200~200,超出范围没有意义,直接与±200 取 Min/Max 即可。
转移方式只有两种:第 i 次挑战成功/失败.
时间复杂度 O(400*n^2)。
30分的暴力算法
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cmath> 5 #include<algorithm> 6 #include<cstring> 7 #include<vector> 8 #include<queue> 9 #include<fstream> 10 using namespace std; 11 int N,L,K; 12 int tmp; 13 int pre[2000];//pre[i]=1 表示第 i次获胜 pre[i]=2表示失败 14 double ans; 15 inline void ser(int,int,int,int);//进行到了第几项 ,赢了几次,有几块碎片,背包总容量 16 inline double calc(); 17 struct node{ 18 int a; 19 double p; 20 }wupin[2000]; 21 inline int cmp(const node &b,const node &c){ 22 if(b.a>c.a) return 1; 23 return 0; 24 } 25 int main(){ 26 // freopen("guard.in","r",stdin); 27 // freopen("guard.out","w",stdout); 28 scanf("%d%d%d",&N,&L,&K); 29 for(int i=1;i<=N;i++){ 30 scanf("%d",&tmp); 31 wupin[i].p=(double)(tmp)/(double)(100); 32 } 33 for(int i=1;i<=N;i++){ 34 scanf("%d",&wupin[i].a); 35 } 36 sort(wupin+1,wupin+N+1,cmp); 37 ser(1,0,0,K); 38 printf("%.6f",ans); 39 return 0; 40 } 41 42 inline void ser(int now,int tot,int sum,int v){ 43 int fro=1; 44 if(wupin[now].a==-1&&v<=sum) fro++;//当前是碎片,但是再加碎片肯定装不进去 45 for(int i=fro;i<=2;i++){ 46 pre[now]=i; 47 if(now==N){ 48 if(i==1){ 49 if(wupin[now].a==-1) sum++; 50 else v+=wupin[now].a; 51 tot++; 52 } 53 if(v>=sum&&tot>=L){//残片可以全部拿走 54 ans+=calc(); 55 } 56 if(i==1){ 57 if(wupin[now].a==-1) sum--; 58 else v-=wupin[now].a; 59 tot--; 60 } 61 } 62 else{ 63 if(i==1){ 64 if(wupin[now].a==-1) ser(now+1,tot+1,sum+1,v); 65 else ser(now+1,tot+1,sum,v+wupin[now].a); 66 } 67 else ser(now+1,tot,sum,v); 68 } 69 } 70 } 71 72 inline double calc(){ 73 double temp=1.000000; 74 for(int i=1;i<=N;i++){ 75 if(pre[i]==1) temp*=wupin[i].p; 76 else if(pre[i]==2) temp=temp*double((double)(1)-wupin[i].p); 77 } 78 return temp; 79 }
100分的dp算法
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cmath> 5 #include<algorithm> 6 #include<cstring> 7 #include<vector> 8 #include<queue> 9 #include<fstream> 10 using namespace std; 11 int N,L,K; 12 int tmp; 13 struct node{ 14 int a; 15 double p; 16 }A[2000]; 17 double f[201][201][401];//f[i][k][j]=e 表示前 i件物品,共赢 k次,当前要装入所有碎片时容量为 j时的概率 18 double ans; 19 int main(){ 20 // freopen("guard.in","r",stdin); 21 // freopen("guard.out","w",stdout); 22 scanf("%d%d%d",&N,&L,&K); 23 for(int i=1;i<=N;i++){ 24 scanf("%d",&tmp); 25 A[i].p=(double)(tmp)/(double)(100); 26 } 27 for(int i=1;i<=N;i++) scanf("%d",&A[i].a); 28 if(K>=400){ 29 K=400; 30 f[0][0][K]=1; 31 } 32 else{ 33 f[0][0][200+K]=1; 34 } 35 36 for(int i=1;i<=N;i++){ 37 for(int j=0;j<=i;j++){ 38 for(int v=1;v<=400;v++){ 39 f[i][j][v]=f[i-1][j][v]*(1-A[i].p); 40 if(j==0) continue;//目前一场都没赢过 41 //下面表示赢 42 if(A[i].a==-1) f[i][j][v]+=f[i-1][j-1][v+1]*A[i].p; 43 else if(v-A[i].a>=0) f[i][j][v]+=f[i-1][j-1][v-A[i].a]*A[i].p; 44 } 45 } 46 } 47 for(int i=L;i<=N;i++) 48 for(int j=200;j<=400;j++) ans+=f[N][i][j] ; 49 printf("%.6f",ans); 50 return 0; 51 }