POJ 2923 Relocation(状压DP+01背包问题)

Description
已知n件货物的重量,先要用两个载重量分别为c1和c2的卡车装载这些货物,问最少需要装载几次
Input
第一行为一整数T表示用例组数,每组用例第一行为三个整数n,c1和c2分别表示货物数量以及两辆卡车的载重量,第二行n个整数表示这n件物品的重量
Output
对于每组用例,输出将这些货物装载完毕所需的最少装载次数,每组用例后跟一空行
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

Solution
枚举2^n种状态,从中找出可以一次被两辆卡车一次装完的状态并记录,将这些状态看作物品,重量为状态,价值为1,那么问题转化为01背包问题,转移方程dp[j|sta[i]]=min(dp[j|sta[i]],dp[j]+1),答案即为dp[(1<

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define INF 1<<30
int t,n,c1,c2,w[10],dp[1<<10],sta[1<<10],res;
bool check(int x)
{
    bool vis[1<<10];//标记数组 
    int sum=0;
    for(int i=1;i<=c1;i++)//初始化 
        vis[i]=0;
    vis[0]=1;
    for(int i=0;i<n;i++)
        if((1<<i)&x)
        {
            sum+=w[i];//此种状态的所运货物的总重量 
            for(int j=c1-w[i];j>=0;j--)
                if(vis[j])//j重量可以运那么j+w[i](<=c1)重量也可以运 
                    vis[j+w[i]]=1;
        }
    for(int i=c1;i>=0;i--)//枚举c1车所运货物重量寻找合法解 
        if(vis[i]&&sum-i<=c2)//找到合法解 
            return true;
    return false;//无解 
}
int main()
{
    scanf("%d",&t);
    for(int test=1;test<=t;test++)
    {
        scanf("%d%d%d",&n,&c1,&c2);
        if(c1>c2)swap(c1,c2);
        for(int i=0;i<n;i++)
            scanf("%d",&w[i]);
        res=0;
        for(int i=0;i<1<<n;i++)//枚举所有状态找到合法状态 
            if(check(i))
                sta[res++]=i;
        for(int i=0;i<1<<n;i++)//初始化 
            dp[i]=INF;
        dp[0]=0;
        for(int i=0;i<res;i++)//01背包 
            for(int j=(1<<n)-1-sta[i];j>=0;j--)
                if(!(j&sta[i]))
                    dp[j|sta[i]]=min(dp[j|sta[i]],dp[j]+1);
        printf("Scenario #%d:\n",test);
        printf("%d\n\n",dp[(1<<n)-1]);
    }
    return 0;
}

你可能感兴趣的:(POJ 2923 Relocation(状压DP+01背包问题))