题意: 有n个目标, n种导弹, 第i种导弹只能打第i个目标, 给出每种导弹命中的概率, 每种导弹的成本(元/个), 总价值为
总成本为
问在总价值不小于s的情况下, 最小成本是多少.
思路:
①概率问题: 假设某火箭发射k次, 全都没命中的概率是 , 那么命中的概率就是
, 那么一种火箭的价值贡献就是
, 一种火箭的成本就是
.
②考虑dp dp[i]表示当前总花费, i表示当前的最大总价值.
③递推式:
④初始化: 将每一个价值都置为inf, 表示要付出无穷大的花费才能达到当前价值.dp[0]=0, 0价值当然不需要花费就能达到.
⑤顺序:
每种导弹->每个价值从大到小->此种导弹的个数.
原因: 将当前种类的导弹的影响都考虑完,再考虑下一种导弹.
每个价值从大到小 保证 只用之前导弹得到的代价 更新 当前状态的代价. 如果从小到大更新, 因为dp数组只有1维, 不可避免的, 就会让已经更新过x类导弹的低状态影响到高状态.我们要保证每个状态都是由没有此类导弹的状态得到, 而背包都是由低状态得到高状态, 所以要先枚举高状态(此时低状态都是未更新的), 再更新低状态.
另外, 最后两维也不能反, 每种炮弹的个数只能有一次贡献, 而如果先枚举个数再枚举价值的话, 某状态可能受到两次不同个数导弹的影响而改变.
⑥如果 低价值的成本>高价值的成本, 那么 高价值的成本就可以赋给低价值的成本(因为如果小的成本就能得到大的价值, 那么他当然能的到小的价值).
代码:
#include<bits/stdc++.h>
#define fuck(x) std::cout<<"["<<#x<<"->"<<x<<"]"<<endl;
using namespace std;
typedef long long ll;
const int M=2e5+5;
const int inf=1e9+5;
const int mod=1e9+7;
//memset(a,0x3f,sizeof(a));
int dp[50005];
// dp[i]=dp[ i - w[j]*(1- ( 1- p[j]) ^k) ] + v[j] *k
int n,m,s;
int w[505];
int v[505];
double p[505];
int sum=0;
int main() {
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++) {
scanf("%d",&w[i]);
sum+=w[i];
}
for(int i=1; i<=n; i++) {
scanf("%d",&v[i]);
}
for(int i=1; i<=n; i++) {
scanf("%lf",&p[i]);
}
fill(dp,dp+50005,inf);
dp[0]=0;
for(int j=1; j<=n; j++) {
for(int i=sum; i>=0; i--) {
double tmp=1;
for(int k=0; k<=10; k++) {
int now=round(w[j]*(1- tmp ));
if(i>=now)
dp[i]=min(dp[i],dp[ i - now ] + v[j] * k );
tmp=tmp*( 1- p[j]);
}
}
}
for(int i=sum; i>=0; i--) {
dp[i]=min(dp[i],dp[i+1]);
}
// for(int i=0;i<505;i++){
// printf("[%d]:%d ",i,dp[i]);
// }
// puts("");
for(int i=0; i<m; i++) {
scanf("%d",&s);
if(dp[s]==inf) {
printf("Impossible\n");
} else
printf("%d\n",dp[s]);
}
return 0;
}