您的位置:首页 > 其它

light oj 1147 背包dp+状态压缩 好题

2013-11-07 21:04 232 查看
题意:n个物品(2<=n<=100),将n个物品平均分成2堆(n为奇数,两堆个数差1),要你让这两堆的差值尽最小,输出两堆的重量,物品总重量不超过100000。

思考:如何保存两堆物品个数差值是这题的关键。如果没有平均分,那么我们假设sum为总重量, 搞个sum/2的背包去装,dp结束以后就O(sum/2)扫一遍。 

分析: 但这里要求平均分,我们想想没有平均分的做法dp里面的值是bool型的,这题我们可以扩增dp里面的值,来保存我装满了j的背包是由几个物品构成的,当然要记录所有的组合情况,考虑到n只有100,对半分后就是50, dp开个long long,  用一个二进制数表示   装满了j的背包是由几个物品构成的,
比方说由3个物品构成,那么dp的第三位二进制位为1,否则为0, 然后就可以转移了。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
typedef long long ll;
int n, a[101];
int sum, m, s;
ll dp[50004], mask;
int main() {
int i, j, cas, ca = 1;
scanf("%d", &cas);
while(cas--) {
scanf("%d", &n);
sum = 0;
mask = (1LL<<((n>>1)+2))-1;
for(i = 0; i < n; i++)
scanf("%d", &a[i]), sum += a[i];
m = sum >> 1;
for(i = 0; i <= m; i++) dp[i] = 0;
dp[0] = 1;
for(i = 0; i < n; i++)
for(j = m; j >= a[i]; j--) if(dp[j-a[i]])
dp[j] |= (dp[j-a[i]]<<1)&mask;
printf("Case %d: ", ca++);
ll x = 1LL << (n/2);
ll y = 1LL << ((n+1)/2);
for(i = m; i >= 0; i--)
if(dp[i]&x || dp[i]&y) {
printf("%d %d\n", i, sum-i);
break;
}

}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: