POJ - 2923 Relocation 01背包+状态压缩

题意

有n个物品体积为wi,两辆车容量分别为c1,c2,求最少要运几次;

思路

可以将一次两辆车装的物品总数当作单个状态,这样就转化为了,不重不漏取所有物品需要几步的状压dp;
枚举所有状态state(0<=state<=(1<<n)),我们可以根据每个state中1的位置求的这个状态求得当前状态物品总体积,再判断可以保存当前状态的车;
之后枚举两辆车所有装载状态进行组合,求的两车一起运输的所有状态;
转移方程
dp[j|i]=min(dp[j|i],dp[j]+1);
j是当前以取物品状态,i是当前车的装载状态,j|i是下次车的装载状态;

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=10,M=1<<10;
const int INF=1e9;
int n,c1,c2,cnt1,cnt2;
int w[N];
int state1[M];
int state2[M];
int state[M];
int dp[M];
int main()
{
    int T;
    scanf("%d",&T);
    for(int cas=1; cas<=T; cas++)
    {

        fill(dp,dp+M,INF);
        fill(state,state+M,0);

        scanf("%d%d%d",&n,&c1,&c2);
        for(int i=0; i<n; i++)
            scanf("%d",&w[i]);
        //预处理两辆车各自装载方案
        cnt1=cnt2=0;
        for(int i=0; i<(1<<n); i++)
        {
            int sum=0;
            for(int j=0; j<n; j++)
                if((i>>j)&1)
                    sum+=w[j];
            if(sum<=c1)state1[cnt1++]=i;
            if(sum<=c2)state2[cnt2++]=i;
        }
        //合并两辆车的装载方案,因为组合起来会有重复,所以这里不离散化
        for(int i=0; i<cnt1; i++)
            for(int j=0; j<cnt2; j++)
                state[state1[i]|state2[j]]=1;

        dp[0]=0;//起点
        for(int i=0; i<(1<<n); i++)
            if(state[i])//代表i状态可以装载
                for(int j=0; j<(1<<n); j++)
                    if(((j&i)==0)&&dp[j]!=INF)//起点要被更新过
                        dp[j|i]=min(dp[j|i],dp[j]+1);

        printf("Scenario #%d:\n%d\n\n",cas,dp[(1<<n)-1]);
    }
    return 0;
}

发布了20 篇原创文章 · 获赞 21 · 访问量 980

猜你喜欢

转载自blog.csdn.net/qq_44086097/article/details/104213580
今日推荐