• POJ 2923 Relocation 装车问题 【状态压缩DP】+【01背包】


    题目链接:https://vjudge.net/contest/103424#problem/I

    转载于:>>>大牛博客

    题目大意:

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

    解题分析:

    物品个数最多是10个,可以用0和1分别表示物品是否被选中运送

    假设有3个物品,那么可以用001表示当前这一次选择将第3个物品运走

    那么,所有的状态可以用0~2^n-1对应的二进制数表示出来

    对于上述每一种状态,选择其中可以一次运走的状态进行01背包

    其中,所有位全部为1的二进制数表示背包总体积

    每个物品的体积是该状态对应二进制数中1的个数

    为了把物品全部运走,要选择一些状态把背包的1全部被填满

    值得注意的是,因为一件物品不会被运2次,所以所有选取的状态应该是没有交集的

    比如1001101和1110010是不行的,第一件物品被运了2次

    然后为了使次数最小,可以将次数抽象成01背包中的物品价值,每种状态对应运送一次,价值是1

     

    如何判断某种状态是否可以一次运走?

    因为有2辆车,所以将要判断该状态是否能分成满足体积分别小于等于车体积的2份,

    如何从十进制中取出该状态被选择的物体?

    也就是将二进制中的1的位置取出来

    利用 :>> :右移运算符 << 左移运算符  & 按位与运算符

    假设有一个二进制数: x  =  01101

    那么将它右移2位  : x>>=2,他会变成 00011(移出位被丢弃,左边移出的空位或者一律补0,或者补符号位)

    我们知道1的二进制数是最后一位为1其他全为0,如果某数的二进制从又往左数第2位是1,移位之后这个1

    变成最后一位,和二进制只有最后一位是1的数字1&之后还是1,而如果某数的二进制从又往左数第2位是0

    的话,和二进制只有最后一位是1的数字1&之后将是0(因为1除了最后一位其他位全为0,而该数移位后最后一位是0)

    综上所述      (x>>i)&1可以判断x从右往左第i位是0还是1【同理(x&(1<<i))也可以判断】

    知道怎么找到二进制数中1的位置基本状压的代码也不难懂了

    #include<iostream>  
    #include<algorithm>  
    #include<string>  
    #include<cstring>  
    #include<cstdio>  
    #include<cmath>  
    #define mem(a,x) memset(a,x,sizeof(a))  
    #define inf 1<<30  
    using namespace std;  
    const double PI = acos(-1.0);  
    typedef long long LL;  
    int state[1030];  
    int dp[1030];  
    bool vis[1005];  
    int n,v1,v2,tot;  
    int c[12];  
    bool ok(int x)//判断一种状态是否可行(可以一次运走)  
    {  
        int sun = 0;  
        mem(vis,0);  
        vis[0] = 1;  
        for (int i = 0;i < n;i++)  
        {  
            if ((x>>i)&1)  
            {  
                sun += c[i];  
                for (int j = v1;j >= c[i];j--) //这个真的非常巧妙 开始看半天都不懂,自己模拟一遍才懂  
                {                              //比如说此状态有c1、c2、c3,3个体积,第一次操作把体积c1标记为1,  
                      if (vis[j-c[i]])         //第二次操作把c2和c1+c2两种体积标记为1,第三次把c3和前面的组合标记为1,  
                        vis[j] = 1;            //最后这些体积能组合成的所有体积就都被标记成了1  
                }  
            }  
        }  
        if (sun > v1+v2)//装不下  
            return 0;  
        //总体积小不代表一定装得下,拆分成2份要2份都装得下  
        for (int i = 0;i <= v1;i++)  
        {  
            if (vis[i]&&sun-i <= v2)//如果存在(i,sun-i)这样的组合  
                return 1;           //满足i可以被v1装下(前面for循环是对于v1的,vis[i]表示体积i可以被v1装下),sun-i可以被v2装下  
        }  
        return 0;  
    }  
    void init()//初始化找到满足条件的状态  
    {  
        tot = 0;  
        for (int i = 1;i < (1<<n);i++)  
        {  
            dp[i] = inf;  
            if (ok(i))  
                state[tot++] = i;  
        }  
    }  
    int main()  
    {  
        int T;  
        cin>>T;  
        int oo = 0;  
        while (T--)  
        {  
            cin>>n>>v1>>v2;  
            for (int i = 0;i < n;i++)  
                scanf("%d",&c[i]);  
            init();  
            int V = (1<<n) - 1;//V是n个1的二进制数  
            dp[0] = 0;//没有物品当然是0次运走  
            for (int i = 0;i < tot;i++)  
            {  
                for (int j = V;j >= 0;j--)  
                {  
                    if (dp[j] == inf)  
                        continue;    //原版的背包是dp[j] = min(dp[j],dp[j-c[i]]+w[i])  
                                      //但是显然二进制不好表示减,但是可以用|抽象加  
                                      //这就相当于背包改版成dp[j+c[i]] = min(dp[j+c[i]],dp[j] + w[i])  
                    if ((j&state[i])==0) //当然2种状态不能有交集  
                    {  
                        dp[j|state[i]] = min(dp[j|state[i]] ,dp[j] + 1);  
                    }  
      
                }  
            }  
            printf("Scenario #%d:
    %d
    ",++oo,dp[V]);  
            if (T) puts("");  
        }  
        return 0;  
    }  

    2018-05-13

  • 相关阅读:
    Kubernetes学习之路(21)之网络模型和网络策略
    Kubernetes学习之路(16)之存储卷
    Kubernetes学习之路(18)之statefulset控制器
    Kubernetes学习之路(28)之镜像仓库Harbor部署
    Kubernetes学习之路(六)之创建K8S应用
    Kubernetes学习之路(十五)之Ingress和Ingress Controller
    nali一款linux下显示IP来源的小工具
    Redis 及RedisBloom 安装
    对java注解与反射的理解
    Java 8 stream的详细用法
  • 原文地址:https://www.cnblogs.com/00isok/p/9032848.html
Copyright © 2020-2023  润新知