背包dp(01)
Posted showend
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了背包dp(01)相关的知识,希望对你有一定的参考价值。
01背包
http://acm.hdu.edu.cn/showproblem.php?pid=2546
余额为体积;
01背包比较明显;
因为是>=5时才能消费,所以预留5的空间,计算出在余额为m-5的情况下,所能花费的最大价钱;
记住,因为只要>=5,不管菜多贵,都能买;所以我们希望5元时买的菜最贵;所以排序,只计算前n-1个菜获得的最大值,再加上最后一个即可;
还有个特判m<5时
#include<bits/stdc++.h> using namespace std; #define int long long const int inf=0x7f7f7f; int t,n,m; int dp[1011],val[1010]; signed main() { while(scanf("%d",&n)!=EOF) { if(n==0) break; memset(val,0,sizeof(val)); for(int i=1;i<=n;i++) cin>>val[i]; memset(dp,0,sizeof(dp)); scanf("%d",&m); if(m<5) {cout<<m<<endl;continue;} sort(val+1,val+1+n); dp[0]=0; for(int i=1;i<=n-1;i++) { for(int j=m-5;j>=val[i];j--) { if(dp[j]<dp[j-val[i]]+val[i]){ dp[j]=dp[j-val[i]]+val[i]; } } } cout<<m-(dp[m-5]+val[n])<<endl; } }
间接求值
http://acm.hdu.edu.cn/showproblem.php?pid=2955
有小数,很明显,p不能作为数组下标的值;
如果抢劫银行最多能抢x,对于抢这么多钱x有个被抓的概率px;
只要px<=p即可;
而对于不被抓的概率,比较难算,因为不具独立性;
比如两个抢劫事件A,被抓概率PA=0.02,B,PB=0.03;
而被抓的概率=PA*(1-PB)+PB*(1-PA)+PA*PB
不被抓被抓的概率=(1-PA)*(1-PB);
所以dp【j】表示不被抓的概率
#include<bits/stdc++.h> using namespace std; #define int long long const int inf=0x3f; int t,n; int val[1010]; double pro[1010],dp[10101];//dp代表不被发现的概率 signed main() { cin>>t; while(t--) { double p; scanf("%lf %d",&p,&n); int sum=0; memset(dp,0,sizeof(dp)); memset(val,0,sizeof(val)); memset(pro,0,sizeof(pro)); for(int i=1;i<=n;i++) { scanf("%d %lf",&val[i],&pro[i]); sum+=val[i]; } dp[0]=1; for(int i=1;i<=n;i++) { for(int j=sum;j>=val[i];j--) dp[j]=max(dp[j],dp[j-val[i]]*(1.0-pro[i])); } for(int j=sum;j>=0;j--) { if(dp[j]>=(1.0-p)){ cout<<j<<endl;break; } } } }
背包问题中求次优解,第K优解的问题
博客:
https://blog.csdn.net/yandaoqiusheng/article/details/84782655
Bone Collector II
http://acm.hdu.edu.cn/showproblem.php?pid=2639
背包又不是求最值,对于求k大值,dp[v][k]表示容量v时第k大值;
dp[j][k]可以由dp【j-v【i】】【h】+val【i】和dp[j][h]这两个转化过来;
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int inf=0x3f;
map<int,int> mp;
int t,n;
int val[1010],dp[1010][40],v[1010],a[1010],b[1010];
signed main()
{
cin>>t;
while(t--)
{
int n,m,k,sum=0;
cin>>n>>m>>k;
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++) cin>>val[i];
for(int i=1;i<=n;i++) cin>>v[i];
for(int i=1;i<=n;i++)
{
for(int j=m;j>=v[i];j--)
{
int l=1,r=1;
for(int h=1;h<=k;h++)
{
a[h]=dp[j][h];//a,b两个数组记录所有可能的数值
b[h]=dp[j-v[i]][h]+val[i];
}
int p=1;
a[k+1]=-1,b[k+1]=-1;//合并两个序列
while(p<=k&&(a[l]!=-1||b[r]!=-1)){//找出前k个
if(a[l]>b[r]) dp[j][p]=a[l],l++;
else dp[j][p]=b[r],r++;
if(dp[j][p]!=dp[j][p-1]) p++;
}
}
}
cout<<dp[m][k]<<endl;
}
}
以上是关于背包dp(01)的主要内容,如果未能解决你的问题,请参考以下文章