题目链接:http://poj.org/problem?id=2923
题意:给出两部卡车能装的最大容量,还有n件物品的分别的weight。问以最优方式装入并且要两辆卡车一块运输物品,最少能运送的次数是多少。
思路:枚举所有的状态并判断该状态是否可以通过两辆卡车一次运输完,如果可以就将该状态看作一个物品,对于所有物品的组合可以利用类似01背包的思想。比如车载重12,现在有3个物品分别重1,4,7那所有的组合就是(1,4,5,7,8,11)。因为一件物品不可能运两次,所以还要判断是否有交集。dp时可以用 | 运算合并两个状态,状态方程
表示状态为时的最少运输次数。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
#include <queue>
#include <cmath>
#include <set>
using namespace std;
#define inf 0x3f3f3f3f
const int N = 1e3+25;
int n, m, c, k, sum, dp[N], a[N];
int vis[N];
std::vector<int> v;
int judge(int x)
{
memset(vis, 0, sizeof(vis));
vis[0] = 1; sum = 0;
for(int i = 0; i < n; i++)
{
if(x & (1 << i))
{
sum += a[i];
for(int j = m; j >= a[i]; j--)
if(vis[j-a[i]]) vis[j] = 1;
}
}
for(int i = 0; i <= m; i++)
if(vis[i] && sum - i <= c)
return 1;
return 0;
}
void init()
{
dp[0] = 0; v.clear();
for(int i = 1; i < (1 << n); i++)
{
dp[i] = inf;
if(judge(i))
v.push_back(i);
}
}
int main()
{
int t; scanf("%d",&t);
int Case = 1;
while(t--)
{
scanf("%d%d%d",&n, &m, &c);
for(int i = 0; i < n; i++)
scanf("%d",&a[i]);
init(); k = (1 << n) - 1;
for(int i = 0; i < v.size(); i++)
{
for(int j = k; j >= 0; j--)
{
if((v[i] & j) == 0)
dp[j|v[i]] = min(dp[j] + 1, dp[j|v[i]]);
}
}
printf("Scenario #%d:\n%d\n",Case++, dp[k]);
if(t) puts("");
}
}