题意:给出银行的个数和被抓概率上限P。在给出每个银行的钱和抢劫这个银行被抓的概率。
求不超过被抓概率上线能抢劫到最多的钱。
两种方法
方法一:dp[j]为抢劫了j元钱不被抓到概率,状态转移方程dp[j] = max(dp[j], dp[j - w[i]] * p[i])
#include <iostream>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
const int maxn = 10010;
double dp[maxn];
double p[maxn];
int w[maxn];
int main()
{
//freopen("in.txt", "r", stdin);
int T;
int cas = 0;
scanf("%d", &T);
while(T--)
{
int sum = 0;
double P;
int n;
scanf("%lf%d", &P, &n);
for(int i = 1; i <= n; i++)
{
scanf("%d%lf", &w[i], &p[i]);
p[i] = 1.0-p[i];
sum += w[i];
}
for (int i = 0; i <= sum; i++)
{
dp[i] = 0;
}
dp[0] = 1.0; //没有枪钱那么不被抓的概率就是1
for(int i = 1; i <= n; i++)
{
for(int j = sum; j >= w[i]; j--)
{
if (dp[j - w[i]]) { //当dp[j - w[i]>0才有比较的必要,不然dp[j - w[i]] * p[i]=0,这样做更加省时。
dp[j] = max(dp[j], dp[j - w[i]] * p[i]);
}
}
}
for(int i = sum; i >= 0; i--)
{
if(1-dp[i] <= P)
{
printf("Case %d: %d\n", ++cas, i);
break;
}
}
}
return 0;
}
方法二:
dp[i][j]表示前 i 个银行抢劫到 j 这么多钱被抓的概率。
转移方程 dp[i][j] = min(dp[i-1][j] , dp[i-1][j-v[i]])
#include<cstdio>
#include<algorithm>
using namespace std;
double d[111][11100];
int main(){
int t,n,x[111];
double p,y[111];
scanf("%d",&t);
for(int cse=1; cse<=t; ++cse){
scanf("%lf%d",&p,&n);
int sum=0;
for(int i=1; i<=n; ++i){
scanf("%d%lf",x+i,y+i);
sum+=x[i];
}
for(int i=0; i<=n; ++i){
for(int j=0; j<=sum; ++j) d[i][j]=1;
}
d[0][0]=0;
for(int i=1; i<=n; ++i){
for(int j=0; j<=sum; ++j){
if(j>=x[i]) d[i][j]=min(d[i-1][j],d[i-1][j-x[i]]+(1-d[i-1][j-x[i]])*y[i]);
else d[i][j]=d[i-1][j];
}
}
for(int i=sum; i>=0; --i){
if(d[n][i]<p){
printf("Case %d: %d\n",cse,i);
break;
}
}
}
return 0;
}