POJ 2923 Relocation【状态压缩DP+01背包】

题意: 有 n 个货物,并且知道了每个货物的重量,每次用载重量分别为c1,c2的火车装载,问最少需要运送多少次可以将货物运完。

分析: 找出所有状态(1.....(1<<n)-1)中选出可以用两辆车一次运完的状态

        把每个状态都看作一个物品,重量为该状态的总重量,价值为 1

        求解 01 背包,dp[(1<<n)-1]为最优解

        转移方程: dp[stat|j]=min(dp[stat|j],dp[j]+1)  注意 stat 和 j 不能有交集

#include<stdio.h>
#include<string.h>
#define clr(x)memset(x,0,sizeof(x))
#define min(a,b)(a)<(b)?(a):(b)
#define INF 0x1f1f1f1f
int dp[1<<11];
int a[1<<11];
int v[1<<11];
int w[111];
int st,top,n;
int c1,c2;
int ok(int stat)
{
    int s=0;
    clr(v);
    v[0]=1;
    int i,j;
    for(i=0;i<n;i++)
        if((1<<i)&stat)
        {
            s+=w[i];
            if(s>c1+c2)
                return 0;
            for(j=c1;j>=w[i];j--)
                if(v[j-w[i]])
                    v[j]=1;
        }
    for(i=0;i<=c1;i++)
        if(s-i<=c2&&v[i])
            return 1;
    return 0;
}
int main()
{
    int t,i,j,ca=1;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d",&n,&c1,&c2);
        for(i=0;i<n;i++)
            scanf("%d",&w[i]);
        memset(dp,INF,sizeof(dp));
        dp[0]=0;
        st=(1<<n)-1;
        top=0;
        for(i=1;i<=st;i++)
            if(ok(i))
                a[top++]=i;
        for(i=0;i<top;i++)
            for(j=st;j>=0;j--)
                if(dp[j]!=INF)
                {
                    if(j&a[i])    //  两个状态不能有交集
                        continue;
                    dp[a[i]|j]=min(dp[a[i]|j],dp[j]+1);
                }
        printf("Scenario #%d:\n%d\n\n",ca++,dp[st]);
    }
    return 0;
}
posted @ 2012-09-14 22:10  'wind  阅读(858)  评论(0编辑  收藏  举报