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

题目链接:

https://vjudge.net/problem/POJ-2923

题目大意:

有n个货物,给出每个货物的重量,每次用容量为c1,c2的火车运输,问最少需要运送多少次可以将货物运完

思路:

第一次做状态压缩(状态压缩基础知识传送门

本题的解题思路是先枚举选择若干个时的状态,总状态量为1<<n,判断这些状态集合里的那些物品能否一次就运走,如果能运走,那就把这个状态看成一个物品。预处理完能从枚举中找到tot个物品,再用这tol个物品中没有交集(也就是两个状态不能同时含有一个物品)的物品进行01背包,每个物品的体积是state[i](state[i]表示一次可以运完状态i的物品,i的二进制表示i这个状态的物品),价值是1,求包含n个物品的最少价值也就是dp[(1<<n)-1](dp[i]表示状态i需要运的最少次数)。

状态转移方程:dp[j|k] = min(dp[j|k],dp[k]+1) (k为state[i],1<=j<=(1<<n)-1])。

 1 #include<iostream>
 2 #include<vector>
 3 #include<queue>
 4 #include<algorithm>
 5 #include<cstring>
 6 #include<cstdio>
 7 #include<set>
 8 #include<cmath>
 9 using namespace std;
10 typedef pair<int, int> Pair;
11 typedef long long ll;
12 const int INF = 0x3f3f3f3f;
13 const int maxn = 2000+10;
14 int T, n, m1, m2;
15 int a[20], cnt[maxn], dp[maxn], tot, cases;
16 bool vis[maxn];
17 bool judge(int x)
18 {
19     int sum = 0;
20     memset(vis, 0, sizeof(vis));//vis[i]=1表示m1的车子中可以凑出体积为i的物品
21     vis[0] = 1;
22     for(int i = 0; i < n; i++)
23     {
24         if(x & (1 << i))//第i件物品存在
25         {
26             sum += a[i];
27             for(int j = m1; j >= a[i]; j--)
28                 if(vis[j - a[i]])vis[j] = 1;//此处必须是逆序,因为更新vis[j]的时候要用到vis[j-a[i]],和01背包是一样的
29         }
30     }
31     for(int i = 0; i <= m1; i++)
32     {
33         if(vis[i] && sum - i <= m2)//确保全部物品可以一次性放在两个车子里面
34             return true;
35     }
36     return false;
37 }
38 void init()
39 {
40     memset(dp, INF, sizeof(dp));
41     dp[0] = 0;
42     for(int i = 1; i < (1 << n); i++)
43     {
44         if(judge(i))
45         {
46             cnt[tot++] = i;
47         }
48     }
49 }
50 int main()
51 {
52     cin >> T;
53     while(T--)
54     {
55         cin >> n >> m1 >> m2;
56         tot = 0;
57         for(int i = 0; i < n; i++)cin >> a[i];
58         init();/*
59         for(int i = 0; i < tot; i++)
60             cout<<cnt[i]<<endl;*/
61         for(int i = 0; i < tot; i++)//枚举物品
62         {
63             for(int j = (1 << n) - 1; j >= 0; j--)//逆序枚举状态也是因为dp[j]的更新需要先用到dp[j-***]
64             {
65                 if(dp[j] == INF)continue;
66                 if((j & cnt[i]) == 0)//两者无交集
67                     dp[j | cnt[i]] = min(dp[j | cnt[i]], dp[j] + 1);
68                 //dp[j | cnt[i]]表示j这个状态加上第i件物品的值,可以从dp[j]+1推过去
69             }
70         }
71         printf("Scenario #%d:\n", ++cases);
72         printf("%d\n\n", dp[(1<<n) - 1]);
73
74     }
75 }

原文地址:https://www.cnblogs.com/fzl194/p/8810020.html

时间: 2024-10-13 14:38:54

POJ-2923 Relocation---01背包+状态压缩的相关文章

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

题目链接 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.

poj 2923 Relocation 解题报告

题目链接:http://poj.org/problem?id=2923 题目意思:给出两部卡车能装的最大容量,还有n件物品的分别的weight.问以最优方式装入,最少能运送的次数是多少. 二进制表示物品状态:0表示没运走,1表示已被运走. 枚举出两辆车一趟可以运出的状态.由于物品是一趟一趟运出来的.所以就可以由一个状态通过两辆车一趟的状态转移到另一个状态. dp[i]=MIN(dp[k]+1).k可以由两车一趟转移到i. 我是参考此人的:http://blog.csdn.net/bossup/a

POJ 2411 Mondriaan&#39;s Dream(状态压缩+深搜)

每一行的填充仅与上一行有关系,每行的目的都是至少填充满上一行. 当填充到i行的时候,i-1行某列没填充必须用竖直的方格填充,这是固定的,剩下其余的则搜索填充. 用2进制的01表示不放还是放 第i行只和i-1行有关 枚举i-1行的每个状态,推出由此状态能达到的i行状态 如果i-1行的出发状态某处未放,必然要在i行放一个竖的方块,所以我对上一行状态按位取反之后的状态就是放置了竖方块的状态. 然后用搜索扫一道在i行放横着的方块的所有可能,并且把这些状态累加上i-1的出发状态的方法数,如果该方法数为0,

poj 3254 Corn Fields ,状态压缩DP

题目链接 题意: 一个矩阵里有很多格子,每个格子有两种状态,可以放牧和不可以放牧,可以放牧用1表示,否则用0表示,在这块牧场放牛,要求两个相邻的方格不能同时放牛,即牛与牛不能相邻.问有多少种放牛方案(一头牛都不放也是一种方案) state[i] 表示对于一行,保证不相邻的方案 状态:dp[i][ state[j] ]  在状态为state[j]时,到第i行符合条件的可以放牛的方案数 状态转移:dp[i][ state[j] ] =Sigma dp[i-1][state'] (state'为符合条

POJ 1038 Bugs Integrated, Inc. 状态压缩DP

题目来源:1038 Bugs Integrated, Inc. 题意:最多能放多少个2*3的矩形 思路:状态压缩DP啊 初学 看着大牛的代码搞下来的  总算搞懂了 接下来会更轻松吧 3进制代表前2行的状态(i行和i-1行)1代表i-1行占位 2代表i行占位 i-1不管有没有占位都不会影响的0代表i行和i-1行都空闲 然后枚举状态dfs更新状态 话说就不能没写深搜了 有点不会了 #include <cstdio> #include <cstring> #include <alg

[POJ 2411] Mondriaan&#39;s Dream 状态压缩DP

题意 给定一个 n * m 的矩形. 问有多少种多米诺骨牌覆盖. n, m <= 11 . 实现 1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cctype> 5 #define F(i, a, b) for (register int i = (a); i <= (b); i++) 6 #define LL long long 7 inline

hdu6149 Valley Numer II 分组背包+状态压缩

/** 题目:hdu6149 Valley Numer II 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6149 题意: 众所周知,度度熊非常喜欢图. 为了形成山谷,首先要将一个图的顶点标记为高点或者低点. 标记完成后如果一个顶点三元组<X, Y, Z>中, X和Y之间有边,Y与Z之间也有边,同时X和Z是高点,Y是低点,那么它们就构成一个valley. 度度熊想知道一个无向图中最多可以构成多少个valley,一个顶点最多只能出现在一个valley

hdu6125 Free from square 分组背包+状态压缩

/** 题目:hdu6125 Free from square 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6125 题意: 从不大于n的所有正整数中选出至少1个且至多k个使得乘积不包含平方因子,对10^9+7取模. 1≤n,k≤500. 思路: 分组背包+状态压缩 把n个数分成若干组,互斥的放在同一组. 一开始把所有含平方因子的数去除掉,剩下的进行分组. <sqrt(500)的八个素因子,编成八组,分别为包含2,3,5,7,11,13,17,19素

poj 2288 Islands and Bridges_状态压缩dp_哈密尔顿回路问题

题目链接 题目描写叙述:哈密尔顿路问题.n个点,每个点有权值,设哈密尔顿路为 C1C2...Cn,Ci的权值为Vi,一条哈密尔顿路的值分为三部分计算: 1.每个点的权值之和2.对于图中的每一条CiCi+1,加上Vi*Vi+1 3.对于路径中的连续三个点:CiCi+1Ci+2,若在图中,三点构成三角形,则要加上Vi*Vi+1*Vi+2 求一条汉密尔顿路能够获得的最大值,而且还要输出有多少条这种哈密尔顿路. 这道题的状态感觉不是非常难想,由于依据一般的哈密尔顿路问题,首先想到的是设计二维状态,dp[

[POJ 2923] Relocation (动态规划 状态压缩)

题目链接:http://poj.org/problem?id=2923 题目的大概意思是,有两辆车a和b,a车的最大承重为A,b车的最大承重为B.有n个家具需要从一个地方搬运到另一个地方,两辆车同时开,问最少需要搬运几次? 我先想的是我由A车开始搬,搬运能装的最大的家具总重,然后状态压缩记录下搬运了哪些,然后再由B车搬运,状态压缩记录搬运了哪些.以此类推,直到状态满了. 以上方法TLE 然后,实在想不出来了,看了题解:http://blog.csdn.net/woshi250hua/articl