背包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)的主要内容,如果未能解决你的问题,请参考以下文章

把01背包问题的底裤扒个底朝天!!!

会超时的dfs01背包+快一点的一维DP01背包

hdu 2602 dp 01背包

DP01背包

dp背包问题

01背包问题模板代码