题意:有n个(n<=10)物品,两辆车,装载量为c1和c2,每次两辆车可以运一些物品,一起走。但每辆车物品的总重量不能超过该车的容量。问最少要几次运完。

思路:由于n较小,可以用状态压缩来求解。
     家具从左到右依次对应二进制形式的低位到高位,该位上为1表示该家具还没运走,0表示已经运走。
     建立两个数组,s1[],s2[],分别存储一次性能被货车1和货车2运走的状态。
     之后再把s1,s2数组中的状态合并一下,存入到s数组中去,即表示能一次性被两辆货车同时运走的状态。
         合并条件:若(s1&s2)=0,即没有重合的,则两者可以合并

     dp[i]表示剩余家具状态为i时最少要搬几次

     状态转移方程:
     dp[j]=min(dp[j-s[i])+1; //当然(s[i]|j)=0,即s[i]为j的子序列

有两个要注意的地方!!!
  1.先用vis数组,若vis[s1|s2]=1表示该状态(s1与s2合并的状态)可以一次性被两辆车运走,
     之后再把相应的状态存入s1s2数组。
     因为如果直接存储,可能会有几次(s1|s2)数值相同的情况,这样可能在s1s2中存储多个相同的值,这样会对答案有影响。
  2.一开始忽略一点,就是有可能运家具只是用其中一辆货车,另一辆装不下任何货物。。。
     所以状态要从0开始枚举,而不是从1开始。。。

附上两个代码:

01背包,即直接dp方程求解:

#include <iostream>
#include <stdio.h>
#include <cstring>
#include <algorithm> using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=(<<)+;
int n,c1,c2;
int w[];
//s1存储能一次性被货车1运走的状态,s2存储能一次性被货车2运走的状态,s存储能一次性被两辆货车同时运走的状态
int s1[maxn],s2[maxn],s[maxn];
int vis[maxn]; //标记哪些状态可以一次性被两辆货车运走
int idx1,idx2,idx;
int dp[maxn]; void init(){
idx1=idx2=idx=-;
int sum;
//忽略一点,就是有可能之后运家具只是用其中一辆货车,另一辆装不下任何货物。。。
//所以状态要从0开始。。。
for(int i=;i<(<<n);i++){
sum=;
for(int j=;j<n;j++){
if(i&(<<j)){
sum+=w[j];
}
}
if(sum<=c1)
s1[++idx1]=i;
if(sum<=c2)
s2[++idx2]=i;
}
/*
先用vis数组存储哪些能一次性运走,之后在存入s数组.
因为如果直接存入s数组的话,可能有好几组s1[i]|s2[j]相同,这样同一个数会存好几次,可能会有影响
*/
memset(vis,,sizeof(vis));
for(int i=;i<=idx1;i++){
for(int j=;j<=idx2;j++){
if((s1[i]&s2[j])==){
vis[s1[i]|s2[j]]=;
}
}
}
for(int i=;i<(<<n);i++)
dp[i]=INF;
for(int i=;i<(<<n);i++){
if(vis[i]){
s[++idx]=i;
dp[i]=;
}
}
}
int main()
{
int t;
scanf("%d",&t);
for(int q=;q<=t;q++){
scanf("%d%d%d",&n,&c1,&c2);
for(int i=;i<n;i++){
scanf("%d",&w[i]);
}
init();
for(int i=;i<=idx;i++){
for(int j=(<<n)-;j>=s[i];j--){
if((s[i]|j)==j){
dp[j]=min(dp[j],dp[j-s[i]]+);
}
}
}
printf("Scenario #%d:\n",q);
printf("%d\n\n",dp[(<<n)-]);
}
return ;
}

dfs记忆化搜索:

#include <iostream>
#include <string.h>
#include <algorithm>
#include <stdio.h> using namespace std; int s1[];//存储可以被c1货车一次性搬走的家具的不同状态,二进制下1代表还没搬,0代表已搬走了
int s2[];//存储可以被c2货车一次性搬走的家具的不同状态,二进制下1代表还没搬,0代表已搬走了
int s1s2[];//存储可以一次性被两辆车运载的情况
int vis[];//vis[i]:若i能一次性被两辆车运走,则vis[i]=1;
int index1,index2,index3;
int dp[(<<)+];//dp[i]表示剩余家具状态为i时最少要搬几次
int t,n,c1,c2,load;
int w[];
int ans; void init(){
for(int i=;i<(<<n);i++){
load=; //忘记每次开始的时候load=0了;
for(int p=;p<n;p++){
if(i&(<<p)){
load+=w[p];
}
}
if(load<=c1){
s1[index1]=i;
index1++;
}
if(load<=c2){
s2[index2]=i;
index2++;
}
}
} int dfs(int s){
int ss1,ss2;
int ss;
if(dp[s]!=-)
return dp[s];
for(int i=;i<index3;i++){
if(s1s2[i]==s){
dp[s]=;
return dp[s];
}
}
dp[s]=; for(int i=;i<index3;i++){
ss=s1s2[i];
if((ss|s)==s){
dp[s]=min(dp[s],dfs(s-ss)+);
}
}
return dp[s];
}
int main()
{
scanf("%d",&t);
for(int i=;i<=t;i++){
memset(dp,-,sizeof(dp));
memset(vis,,sizeof(vis));
index1=index2=index3=;
scanf("%d%d%d",&n,&c1,&c2);
for(int j=;j<n;j++)
scanf("%d",&w[j]);
init();
int s11,s22;
//先将可以一次性被两辆车运走的情况给存起来
for(int m=;m<index1;m++){
for(int j=;j<index2;j++){
s11=s1[m];
s22=s2[j];
if((s11&s22)==){
vis[s11|s22]=;
}
}
}
for(int m=;m<(<<n);m++){
if(vis[m]==){
s1s2[index3]=m;
index3++;
}
}
ans=dfs((<<n)-);
printf("Scenario #%d:\n",i);
printf("%d\n\n",ans);
}
return ;
}

POJ 2923 Relocation (状态压缩,01背包)的更多相关文章

  1. Relocation - POJ 2923(状态压缩+01背包)

    题目大意:有个人需要搬家,有N件物品,给个物品的重量是 w[i] 然后又两个车,每个车的载重量分别是C1和C2,求最少需要运输多少次才能把这些物品全部运输完毕. 分析:刚开始就发现物品数不多,想着直接 ...

  2. poj 2923 状压dp+01背包

    好牛b的思路 题意:一系列物品,用二辆车运送,求运送完所需的最小次数,两辆车必须一起走 解法为状态压缩DP+背包,本题的解题思路是先枚举选择若干个时的状态,总状态量为1<<n,判断这些状态 ...

  3. BZOJ 4197: [Noi2015]寿司晚宴 状态压缩 + 01背包

    4197: [Noi2015]寿司晚宴 Time Limit: 10 Sec  Memory Limit: 512 MB Description 为了庆祝 NOI 的成功开幕,主办方为大家准备了一场寿 ...

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

    题目链接:https://vjudge.net/contest/103424#problem/I 转载于:>>>大牛博客 题目大意: 有 n 个货物,并且知道了每个货物的重量,每次用 ...

  5. POJ 2184 Cow Exhibition【01背包+负数(经典)】

    POJ-2184 [题意]: 有n头牛,每头牛有自己的聪明值和幽默值,选出几头牛使得选出牛的聪明值总和大于0.幽默值总和大于0,求聪明值和幽默值总和相加最大为多少. [分析]:变种的01背包,可以把幽 ...

  6. poj 3311(状态压缩DP)

    poj  3311(状态压缩DP) 题意:一个人送披萨从原点出发,每次不超过10个地方,每个地方可以重复走,给出这些地方之间的时间,求送完披萨回到原点的最小时间. 解析:类似TSP问题,但是每个点可以 ...

  7. poj 1185(状态压缩DP)

    poj  1185(状态压缩DP) 题意:在一个N*M的矩阵中,‘H'表示不能放大炮,’P'表示可以放大炮,大炮能攻击到沿横向左右各两格,沿纵向上下各两格,现在要放尽可能多的大炮使得,大炮之间不能相互 ...

  8. poj 3254(状态压缩DP)

    poj  3254(状态压缩DP) 题意:一个矩阵里有很多格子,每个格子有两种状态,可以放牧和不可以放牧,可以放牧用1表示,否则用0表示,在这块牧场放牛,要求两个相邻的方格不能同时放牛,即牛与牛不能相 ...

  9. 【bzoj1688】[USACO2005 Open]Disease Manangement 疾病管理 状态压缩dp+背包dp

    题目描述 Alas! A set of D (1 <= D <= 15) diseases (numbered 1..D) is running through the farm. Far ...

  10. POJ.3624 Charm Bracelet(DP 01背包)

    POJ.3624 Charm Bracelet(DP 01背包) 题意分析 裸01背包 代码总览 #include <iostream> #include <cstdio> # ...

随机推荐

  1. 做HDU1010 带出来一个小问题

    做1010  本来是想的DFS深搜  但是自己凭空打  打不出来  因为没有记模板  然后就去搜  但是看了一遍  自己打却又是有BUG  然后验证  就出现了一个二维字符数组打印的问题 开始代码是这 ...

  2. 关于Haproxy安装和配置:负载配置【haproxy.cfg】问题记录

    1.  存放地址: more /etc/haproxy/haproxy.cfg ps -ef | grep haproxy 看看有没有haproxy的进程就是了 或者看看服务器的23306的端口有没有 ...

  3. JavaScript 中怎样判断文本框只能输出英文字母、汉字和数字,不能输入特殊字符!

    JS-只能输入中文和英文2008-11-08 10:17在js中用正则表达式对象(RegExp)判断中文 ^[\u0391-\uFFE5]+$英文 ^[A-Za-z]+$中文和英文/^[\u0391- ...

  4. JVM学习总结五(番外)——JConsole

    之前本来打算结合自己写的小程序来介绍JConsole和VirtualVM的使用的,但是发现很难通过一个程序把所有的场景都体现出来,所以还是决定用书中的典型小例子来讲更加清晰. 一.JConsole的基 ...

  5. Knockout应用开发指南 第一章:入门

    2011-11-21 14:20 by 汤姆大叔, 20165 阅读, 17 评论, 收藏,  编辑 1    Knockout简介 (Introduction) Knockout是一个轻量级的UI类 ...

  6. [转]理解与使用Javascript中的回调函数

    在Javascript中,函数是第一类对象,这意味着函数可以像对象一样按照第一类管理被使用.既然函数实际上是对象:它们能被“存储”在变量中,能作为函数参数被传递,能在函数中被创建,能从函数中返回. 因 ...

  7. ASP运行流程(主要的类笔记)

    个人笔记:参考汤姆大叔的MVC之前那些事系列整理  client端发送页面请求,被IIS的某个进程截获,它根据申请的页面后缀(.aspx)不同,调用不同的页面处理程序(.asp->asp.dll ...

  8. 单元测试篇----cppUnit的安装与使用

    在刚学习单元测试章节的时候,尝试着使用dev—c++来编译cppunit,但一直没成功,也尝试问过同学,一直没有很好的方法,因此浪费了不少时间.今天又耐心的尝式一下,意外成功了.以下是详细的安装步骤: ...

  9. nodejs笔记四--创建一个最简单的 express 应用

    express 是 Node.js 应用最广泛的 web 框架,利用 express 可以实现很多的web应用:首先需要需要得到一个express. 新建一个文件夹叫lesson1,进去里面安装 ex ...

  10. JIRA安装过程中链接mysql的问题!

    测试下我使用的是mysql7.5的版本,JIRA是6.3.6!这是版本引起的问题! 服务器上原生的mysql驱动jar包:Mysql-connector-java-5.1.18-bin 可参考:htt ...