[状压dp][BZOJ3717][PA2014]Pakowanie

题意

你有n个物品和m个包。物品有重量,且不可被分割;包也有各自的容量。要把所有物品装入包中,至少需要几个包?

Input

第一行两个整数n,m(1<=n<=24,1<=m<=100),表示物品和包的数量。 
第二行有n个整数a[1],a[2],…,an,分别表示物品的重量。 
第三行有m个整数c[1],c[2],…,cm,分别表示包的容量。

思路:

首先我们可以贪心地选取前几大的包,(由于物品数<=24,其实只用考虑前24个包即可)

考虑到24的数据 状压显得理所当然。

这题需要维护两个东西,

一个是zhi[s]表示装状态为s的物品需要的最小的包数, 
但是这样没法转移,于是还要维护,  h[s]表示对应zhi[s],最后一个包剩下的空间。 

zhi[s]从zhi[t]而来(t为s任意去掉一个1),若zhi[t]+1值更小,更新,或者zhi[t]+1==zhi[s]值相同,h[t]更大,更新

可是为什么这样就可以了

考虑一个状态,其实在转移过程中,你考虑了这个状态的每一种放物品顺序

比如取物品2.4 在状态转移zhi[10]  时 肯定是从 zhi[2] 和zhi[8] 分别转移过来的

这就是和贪心的区别(感觉这就是状压的妙处)

#include<bits/stdc++.h>
using namespace std;
int   n,m,h,h1,f,i1,i2,zhi[20000000],ret[20000000],w[20000000],sum[1000],a[100];
bool  cmp(int a1,int b1)
{ return a1>b1;}
int main()
{
   cin>>n>>m;
   for (int i=1;i<=n;i++)  cin>>a[i];
   for (int i=1;i<=m;i++)  cin>>sum[i];
   sort(sum+1,sum+1+m,cmp);
  for (int i=1;i<1<<n;i++) 
   w[i]=w[i>>1]+1;
  memset(zhi,0x3f,sizeof(zhi));
  zhi[0]=0;
   for (int i=1;i<1<<n;i++)
     {  i2=i;
     for (int j=w[i];j;j=w[i2])
     {  f=0;
        i2=i2-(1<<(j-1));
        i1=i-(1<<(j-1));
        //cout<<i<<' '<<i1<<' '<<i2<<endl;
        if (a[j]<=ret[i1])  {h=zhi[i1]; h1=ret[i1]-a[j];}
                  else {h=zhi[i1]+1;
                        if (sum[h]<a[j] || h>m)  f=1; 
                        h1=sum[h]-a[j];}
        if(!f)   
        {if (h<zhi[i]) {  zhi[i]=h; ret[i]=h1;}
             else {  if (zhi[i]==h)  ret[i]=max(ret[i],h1);}}       
     }
     }
    if (zhi[(1<<n)-1]<=m) cout<<zhi[(1<<n)-1]<<endl;  else cout<<"NIE"<<endl;
 }

小拓展以示区别  背包问题

放一个我觉得有代表意义的

多重背包问题:

多重背包问题描述:有编号分别为a,b,c的三件物品,它们的重量分别是1,2,2,它们的价值分别是6,10,20,他们的数目分别是10,5,2,现在给你个承重为 8 的背包,如何让背包里装入的物品具有最大的价值总和?

多重背包和01背包、完全背包的区别:多重背包中每个物品的个数都是给定的,可能不是一个,绝对不是无限个。

有两种解法,解题思路:

  1. 作为一个新问题考虑,由于每个物品多了数目限制,因此初始化和递推公式都需要更改一下。初始化时,只考虑一件物品a时,f[1][j] = min{num[1], j/weight[1]}。 计算考虑i件物品承重限制为y时最大价值f[i][y]时,递推公式考虑两种情况,要么第 i 件物品一件也不放,就是f[i-1][y], 要么第 i 件物品放 k 件,其中 1 <= k <= (y/weight[i]),考虑这一共 k+1 种情况取其中的最大价值即为f[i][y]的值,即f[i][y] = max{f[i-1][y], (f[i-1][y-k*weight[i]]+k*value[i])}。 这里为什么不能像完全背包一样直接考虑f[i][y-weight[i]]+value[i]呢?因为这样不容易判断第 i 件物品的个数是否超过限制数量 num[i]

其实就是普通dp,前不久了解到它是NPC问题,而之所以我们能o(n*m)解决,是因为限制了背包容量大小。

猜你喜欢

转载自blog.csdn.net/zzrh2018/article/details/81592560