您的位置:首页 > 其它

POJ - 3039 MARGARITAS ON THE RIVER WALK

2015-03-03 11:26 267 查看
题目连接

题意::给定 n 件物品和一个背包,第 i 件物品的体积为 Vi,背包的容量为 C。 要求把一些物品放入背包使得剩下的物品都放不下,求方案数。 要求复杂度:n*C.

题解:考虑剩下的物品放不下,就是说用最小的也不能放下,所以枚举最小的是谁,然后比这个最小的小的必须要放下,而比最小的大的用0,1背包来算可能情况。枚举最小的同时,dp一直递推过去,而不是一直重算。

重点:理解放不下,枚举谁是剩下最小的。并且用递推过去减少重复计算。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <ctype.h>
#include <limits.h>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#include <set>
#include <bitset>
#define CLR(a) memset(a, 0, sizeof(a))
#define REP(i, a, b) for(ll i = a;i < b;i++)
#define REP_D(i, a, b) for(ll i = a;i <= b;i++)

typedef unsigned long long ll;

using namespace std;

const unsigned long long maxn = 1e3 + 100;//忽略本题中的ull......
unsigned long long n, tot, v[110];
unsigned long long ans, dp[maxn];

bool cmp(ll a, ll b)
{
return a > b;
}

void solve()
{
sort(v + 1, v + 1 + n, cmp);//排序,这样后面的是必须用的,前面的是01背包,可以递推
if(v[1] > tot)//特殊情况。。。如果一个都不能放,叫做没有
{
printf("0\n");
return;
}
ll lft = 0;
for(ll i = 1; i <= n; i++)
{
lft += v[i];
}
ans = 0;
CLR(dp);
dp[0] = 1;
for(ll i = 1; i <= n; i++)
{
lft -= v[i];
if(tot >= lft)//其实就是把i当成剩下最小的,而后来的用了lft的空间,只剩<span style="font-family: Arial, Helvetica, sans-serif;">tot - lft - v[i] + 1到tot-lft可以用了,只是ull写的麻烦。</span>
{
if(tot + 1 >= lft + v[i])
{
for(ll j = tot - lft - v[i] + 1; j <= tot - lft; j++)
{
ans += dp[j];
}
}
else
{
for(ll j = 0; j <= tot - lft; j++)
{
ans += dp[j];
}
}
}
for(int j = tot; j >= 0; j--)//递推01背包
{
if(j >= v[i])
{
dp[j] += dp[j - v[i]];
}
}
}
printf("%llu\n", ans);
}

int main()
{
freopen("3Cin.txt", "r", stdin);
//freopen("3Cout.txt", "w", stdout);
ll ncase = 0;
scanf("%llu", &ncase);
for(ll _ = 1; _ <= ncase; _++)
{
printf("%llu ", _);
scanf("%llu%llu", &n, &tot);
REP_D(i, 1, n)
{
scanf("%llu", &v[i]);
}
solve();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: