开始以为是水题目,采用将浮点数乘以100这种昏方法,还是看题解才会写。
这题,首先是对小数背包的处理,显然不能把小数当做容量,那么只能当价值,求出对不同的money,最大的小数是多少,
这样通过边界判断money是否合法,输出合法的最大的money就是背包最终求的价值。
本题一个重点在于状态转移方程。
概率题,显然不同事件是分步的,应该相乘,然后呢,显然一旦被抓,后面就没了,不被抓的概率应该是所有不被抓的累乘。
用1-p处理即可,然后求最大value。
还是一个很好的题目的。
一个背包,如果容量很难处理(数据大或者小数),就可以转换容量和价值,再根据贪心原理求是否合法。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <stack>
#include <queue>
#include <vector>
using namespace std;
typedef long long ll;
const int maxn=100010;
int t,m,n,sum;
double f,dp[10100],v[10100],p;
int w[110];
int main()
{
scanf("%d",&t);
while(t--){
sum=0;
memset(dp,0,sizeof(dp));
scanf("%lf%d",&p,&n);
p=1.0-p;// 将
for(int i=0;i<n;i++){
scanf("%d%lf",&w[i],&v[i]);
v[i]=1.0-v[i];
sum+=w[i];
}
// for(int i=0;i<n;i++) printf("%lf\n",v[i]);
dp[0]=1;//
for(int i=0;i<n;i++){
for(int j=sum;j>=w[i];j--){
dp[j]=max(dp[j],dp[j-w[i]]*v[i]);
}
}
for(int i=sum;i>=0;i--){
// printf("%d\n",dp[i]);
if(dp[i]>=p){
printf("%d\n",i);
break;
}
}
}
return 0;
}
p1064
基本是看题解写出来的,很好理解,但不是那么好写。
本质是改变了了状态转移方程的形式,其他没有什么变化,即,每一步可以选0,1,2,3件(2包含两种情况。
预处理数据(用到了二维数组,以及类似指针的形式)的方式也值得学习。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <stack>
#include <queue>
#include <vector>
using namespace std;
typedef long long ll;
const int maxn=100010;
int n,m,p,q,v;
int dp[33000],f_v[70],s_v[70][10],f_w[70],s_w[70][10],cnt[70];
int main()
{
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>v>>p>>q;
if(!q){
f_w[i]=v;
f_v[i]=p*v;
}else{
cnt[q]++;
s_w[q][cnt[q]]=v;
s_v[q][cnt[q]]=p*v;
}
}
for(int i=1;i<=m;i++){
for(int j=n;f_w[i]>0&&j>=f_w[i];j--){
dp[j]=max(dp[j],dp[j-f_w[i]]+f_v[i]);
if(j>=s_w[i][1]+f_w[i]){
dp[j]=max(dp[j],dp[j-(s_w[i][1]+f_w[i])]+s_v[i][1]+f_v[i]);
}
if(j>=s_w[i][2]+f_w[i]){
dp[j]=max(dp[j],dp[j-(s_w[i][2]+f_w[i])]+s_v[i][2]+f_v[i]);
}
if(j>=s_w[i][2]+s_w[i][1]+f_w[i]){
dp[j]=max(dp[j],dp[j-(s_w[i][2]+s_w[i][1]+f_w[i])]+s_v[i][2]+s_v[i][1]+f_v[i]);
}
}
}
cout<<dp[n]<<endl;
return 0;
}