POJ 3628 Bookshelf 2(状态压缩DP+位运算)

来源:互联网 发布:西瓜影音 mac 编辑:程序博客网 时间:2024/06/11 16:44

Farmer John recently bought another bookshelf for the cow library, but the shelf is getting filled up quite quickly, and now the only available space is at the top.

FJ has N cows (1 ≤ N ≤ 20) each with some height of Hi (1 ≤ Hi ≤ 1,000,000 - these are very tall cows). The bookshelf has a height of B (1 ≤ B ≤ S, where S is the sum of the heights of all cows).

To reach the top of the bookshelf, one or more of the cows can stand on top of each other in a stack, so that their total height is the sum of each of their individual heights. This total height must be no less than the height of the bookshelf in order for the cows to reach the top.

Since a taller stack of cows than necessary can be dangerous, your job is to find the set of cows that produces a stack of the smallest height possible such that the stack can reach the bookshelf. Your program should print the minimal 'excess' height between the optimal stack of cows and the bookshelf.

Input

* Line 1: Two space-separated integers: N and B
* Lines 2..N+1: Line i+1 contains a single integer: Hi

Output

* Line 1: A single integer representing the (non-negative) difference between the total height of the optimal set of cows and the height of the shelf.

Sample Input
5 1631356
Sample Output
1

 【题解】这道题做的很溜,本来对位运算还不怎么懂,今天借助这个题一下就加深了理解,还一次就AC了,不得不说心情爽歪歪~~~

 说一下思路,就是题目给了n个数,要你在这n个数中找到一些数,使他们的和不小于给定的K,并且与K的差值尽量小,输出这个差值,刚开始无从下手的地方是知道要遍历所有的数,找服这些数,但是个数呢?不好控制,而且容易爆数据,这个时候就要想什么东西能够表示每个数取或者不取后的结果呢,相信聪明的读者已经想到了,那就是二进制,1代表取这个数,0代表不取这个数。那么从第一个数开始最少是都不取,那就是0,最多就是全部取,那所有的二进制位全是1,这样的话中间任何情况,以样例为例,构成结果的数字组合是3,3,5,6,那么用二进制表示就是10111,这个结果也在0到11111范围内,所以可以看到,所有的情况都在0到全1的范围内,这样就好办了,全一就是2^5-1,那么我们就可以每次对0~2^5-1的数与1进行按位与&运算,不懂的看这:位运算详解。判断当前位的二进制是不是1,是的话就把它对应的数加起来,最后与16比较,大的话就做差,小的话不用管,最后再遍历一遍求最小值就好。

 【AC代码】

 

#include<iostream>#include<algorithm>#include<cstdio>#include<cstring>using namespace std;const int inf=0x3f3f3f3f;const int N=20;const int maxn=1<<N;int dp[maxn+5];int a[N+4];int m,n;int main(){    scanf("%d%d",&m,&n);    int X=1<<m;    for(int i=1;i<=m;++i)        scanf("%d",&a[i]);    memset(dp,inf,sizeof(dp));    for(int i=0;i<X;++i)    {        int z=i;        int sum=0;        int k=1;        while(z)        {            if((z&1)>0)//判断二进制位是不是1            {                sum+=a[k];//是就加上对应的数组值            }            k++;            z>>=1;//最后一位抹掉        }        dp[i]=min(dp[i],sum>=n?(sum-n):inf);    }    int ans=inf;    for(int i=0;i<X;++i)        if(ans>dp[i])            ans=dp[i];    printf("%d\n",ans);    return 0;}


原创粉丝点击