POJ 2923 Relocation(状态压缩+01背包)

Relocation
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 3627 Accepted: 1489

Description

Emma and Eric are moving to their new house they bought after returning from their honeymoon. Fortunately, they have a few friends helping them relocate. To move the furniture, they only have two compact cars, which complicates everything a bit. Since the furniture does not fit into the cars, Eric wants to put them on top of the cars. However, both cars only support a certain weight on their roof, so they will have to do several trips to transport everything. The schedule for the move is planed like this:

  1. At their old place, they will put furniture on both cars.
  2. Then, they will drive to their new place with the two cars and carry the furniture upstairs.
  3. Finally, everybody will return to their old place and the process continues until everything is moved to the new place.

Note, that the group is always staying together so that they can have more fun and nobody feels lonely. Since the distance between the houses is quite large, Eric wants to make as few trips as possible.

Given the weights wi of each individual piece of furniture and the capacities C1 and C2 of the two cars, how many trips to the new house does the party have to make to move all the furniture? If a car has capacity C, the sum of the weights of all the furniture it loads for one trip can be at mostC.

Input

The first line contains the number of scenarios. Each scenario consists of one line containing three numbers nC1 and C2C1 and C2 are the capacities of the cars (1 ≤ Ci ≤ 100) and n is the number of pieces of furniture (1 ≤ n ≤ 10). The following line will contain n integers w1, …, wn, the weights of the furniture (1 ≤ wi ≤ 100). It is guaranteed that each piece of furniture can be loaded by at least one of the two cars.

Output

The output for every scenario begins with a line containing “Scenario #i:”, where i is the number of the scenario starting at 1. Then print a single line with the number of trips to the new house they have to make to move all the furniture. Terminate each scenario with a blank line.

Sample Input

2
6 12 13
3 9 13 3 10 11
7 1 100
1 2 33 50 50 67 98

Sample Output

Scenario #1:
2

Scenario #2:
3

Source

TUD Programming Contest 2006, Darmstadt, Germany

题意:用容量分别为C1和C2的两辆汽车搬运n个家具,第i个家具的体积为a[i],求出搬运完这n个家具所要的最少次数。

思路:有两辆汽车搬运家具,那么每一次搬运自然是需要选择合适的家具组合能让汽车装的下来。家具最多只有十个,我们如何选择合适的家具装到汽车里呢?我们可以通过状态压缩来解决,通过把n个家具转化为一个二进制数,1表示选择0表示不选择。初始化遍历所有的可能找到能够由两辆汽车装下的状态。那么现在考虑的是怎么判断一个状态能够被两辆汽车装下,我们可以找出所有家具组合其体积之和小于容量C1,然后判断剩余家具是否小于C2,如果满足那么这个状态就是我们要找到。

接下来就是01背包了,把我们之前挑选出来的能够被两辆汽车运走的家具组合当做物品,物品价值为1(求最小搬运次数,搬运一次次数加一)。我们要求的是所有家具被运走,并且是通过一个二进制数来表示那些家具被运走了,比如有五件家具,dp[10011]表示的就是运走第一件、第四件、第五件家具最少的次数。那么我们要找的也就是dp[11111]了,这里要注意家具只能被运一次,那么在用01背包逆序枚举容量的时候要判断一下,代码上有注释。此外一点就是01背包的状态转移方程一般是dp[j]=min(dp[j],dp[j-w[i]]+d[i]),但是我们的j是二进制数,不好用减法,我们可以转换一下,通过“|”来表示加法,那么状态转移方程就是dp[j|state[i]]=min(dp[j|state[i]],dp[j]+1)。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
using namespace std;
const int inf=999999999;
int dp[(1<<10)+5];
int state[(1<<10)+5];
int vis[105],a[15];
int c1,c2,v,n,tot;
int check(int x)
{
    memset(vis,0,sizeof(vis));
    int sum=0;
    vis[0]=1;
    for(int i=0;i<n;i++)
    {
        if((x>>i)&1)
        {
            sum+=a[i];
            //这个循环就是找出容量和小于容量c1的家具组合 乍一看似乎有些不明白
            //自己在脑海或者是用纸笔模拟一遍就明白了,很巧妙的一个方法
            for(int j=c1;j>=a[i];j--)
            {
                if(vis[j-a[i]])
                    vis[j]=1;
            }
        }
    }
    if(c1+c2<sum)//如果总容量两辆车都装不下,那么肯定不满足
        return 0;
    for(int i=0;i<=c1;i++)//总容量小于两辆车的容量并不意味着能被运走,要能分别被两辆车装下才行
    {
        if(vis[i]&&sum-i<=c2)//vis[i]表示容量和为i的家具组合能放进c1,sum是总和
            return 1;
    }
    return 0;
}
void init()
{
    tot=0;
    for(int i=0;i<(1<<n);i++)
    {
        dp[i]=inf;
        if(check(i))
          state[tot++]=i;
    }
}

int main()
{
    int i,j,t,kase=0;
    scanf("%d",&t);
    while(t--)
    {
        memset(state,0,sizeof(0));
        scanf("%d %d %d",&n,&c1,&c2);
        for(i=0;i<n;i++)
            scanf("%d",&a[i]);
        init();
        dp[0]=0;
        v=(1<<n)-1;
        for(i=0;i<tot;i++)
        {
            for(j=v;j>=0;j--)
            {
                if((state[i]&j)==0)//每个家具只能运一次,那么肯定每一位不能重复出现1,通过位运算判断是否重复
                    dp[j|state[i]]=min(dp[j|state[i]],dp[j]+1);
            }
        }
        printf("Scenario #%d:\n%d\n\n",++kase,dp[v]);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值