原题目http://poj.org/problem?id=1014

题目大意

有分别价值为1,2,3,4,5,6的6种物品,输入6个数字,表示相应价值的物品的数量,问一下能不能将物品分成两份,是两份的总价值相等,其中一个物品不能切开,只能分给其中的某一方,当输入六个0是(即没有物品了),这程序结束,总物品的总个数不超过20000

输出:每个测试用例占三行:

第一行: Collection #k: k为第几组测试用例

第二行:是否能分(具体形式见用例)

第三行:空白(必须注意,否则PE)

一:采用第一种深搜方式,如果sum<halfvalue继续往下探索,如果大于则回溯到上一层,证明上一层选的不合适。认真分析就会发现问题,(1)这个树中的搜索路径很明显不支持同一个数字的若干次选取。(2)仅仅只有六层。这怎么可以呢!照此说不管怎么遍历都是1+2+3+4+5+6.

二: 这种搜索是合理的。每次探测都可以有六种选择,也可以想象成从六个盒子里面拿东西,每次从六个盒子里选一种,第一种出现的两种错误都可以避免掉。而且每个节点的度都是6,而且特征一样。这个非常好,对每个节点的处理都一样。很明显可以递归。符合DFS的特点。

解题思路:

有两种解决方法:

第一种是几乎百度上所有同学都热衷的多重背包,确实这题就是《背包九讲》里面的“多重背包”的应用题,直接套O(V*Σlog n[i])的模板就毫无悬念地AC了,《背包九讲》里面提供的是“多重背包+二进制优化”算法,百度上也有不少同学加入了自己的想法去进一步优化,例如利用“抽屉原理”证明并“取模优化”的可行性等,这些同学都做了不少功课,值得我们学习。

第二种方法是几乎没有同学使用的DFS,本题用DFS也能0ms跑完,可能大家都被《背包九讲》冲昏了头脑,都想着套模板去了,但又看不懂模板。呻吟“研究了背包多长时间都不完全明白”的同学不妨试试DFS。其实本来不少DP题都可以用搜索过的,大家不要钻牛角尖。

解法一:DFS

#include<iostream>
using namespace std; int amount[7] = {0};
int half_value = 0;
int flag = 0; void DFS(int value, int pre){ if(value == half_value){
flag = 1;
return;
} if(flag == 1){ // 到某一深度的时候接受到上层的(flag=1),那这层也要继续往上
return;
} int i = 0;
for(i = pre; i > 0; i--){
if(amount[i]){
if(i + value <= half_value){
amount[i]--;
DFS(i + value, i);
<span style="white-space:pre"> </span>//如果搜索到某一深度满足条件
if(flag == 1){ //回到上层
return;
}
}
}
}
} int main(){ int testcase = 1;
while(true){
flag = 0;
int totalvalue = 0;
int N = 6;
int i = 1;
while(i <= N){
cin >> amount[i];
totalvalue += amount[i] * i;
i++;
} if(!amount[1] && !amount[2] && !amount[3] && !amount[4] && !amount[5] && !amount[6]){
break;
} printf("Collection #%d:\n", testcase++);
if(totalvalue % 2 != 0){
cout << "Can't be divided." << endl << endl;
continue;
} half_value = totalvalue / 2;
DFS(0, 6); //注意由于6的价值比较大容易接近所要得的一半
<span style="white-space:pre"> </span>//若取1可能会多走很多
if(flag){
cout << "Can be divided." << endl;
} else {
cout << "Can't be divided." << endl;
}
cout << endl;
}
return 0;
}

(上面这个代码有个bug(题目还是可以AC的)( 0 0 3 0 3 1) 就过不了,上面是不能跳过中间值的,

而数据是要6和3结合于是就呵呵了(求大牛赐教怎么修改)

当然还有解法二:

//Memory Time
//656K 16MS /*多重背包+二进制优化*/ #include<iostream>
using namespace std; int n[7]; //价值为i的物品的个数
int v; //背包容量
int SumValue; //物品总价值
bool flag; //标记是否能平分SumValue
int dp[100000]; //状态数组 int max(int a,int b)
{
return a>b?a:b;
} /*完全背包*/
void CompletePack(int cost,int weight)
{
for(int i=cost;i<=v;i++)
{
dp[i]=max(dp[i],dp[i-cost]+weight);
if(dp[i]==v) //剪枝,当能够平分SumValue时退出
{
flag=true;
return;
}
} return;
} /*01背包*/
void ZeroOnePack(int cost,int weight)
{
for(int i=v;i>=cost;i--)
{
dp[i]=max(dp[i],dp[i-cost]+weight);
if(dp[i]==v) //剪枝
{
flag=true;
return;
}
}
return;
} /*多重背包*/
void MultiplePack(int cost,int weight,int amount)
{
if(cost*amount>=v)
{
CompletePack(cost,weight);
return;
} if(flag) //剪枝
return; /*二进制优化*/
int k=1;
while(k<amount)
{
ZeroOnePack(k*cost,k*weight); if(flag) //剪枝
return; amount-=k;
k*=2;
}
ZeroOnePack(amount*cost,amount*weight); return;
} int main(int i)
{
int test=1;
while(cin>>n[1]>>n[2]>>n[3]>>n[4]>>n[5]>>n[6])
{
SumValue=0; //物品总价值 for(i=1;i<=6;i++)
SumValue+=i*n[i]; if(SumValue==0)
break; if(SumValue%2) //sum为奇数,无法平分
{
cout<<"Collection #"<<test++<<':'<<endl;
cout<<"Can't be divided."<<endl<<endl; //注意有空行
continue;
} v=SumValue/2;
memset(dp,-1,sizeof(dp));
dp[0]=0;
flag=false; for(i=1;i<=6;i++)
{
MultiplePack(i,i,n[i]); if(flag) //剪枝
break;
} if(flag)
{
cout<<"Collection #"<<test++<<':'<<endl;
cout<<"Can be divided."<<endl<<endl;
continue;
}
else
{
cout<<"Collection #"<<test++<<':'<<endl;
cout<<"Can't be divided."<<endl<<endl;
continue;
}
}
return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

DFS(DP)---POJ 1014(Dividing)的更多相关文章

  1. POJ 1014 Dividing

    Dividing Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 66032 Accepted: 17182 Descriptio ...

  2. POJ 1014 Dividing(多重背包)

    Dividing   Description Marsha and Bill own a collection of marbles. They want to split the collectio ...

  3. POJ 1014 Dividing 多重背包

    Dividing Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 63980   Accepted: 16591 Descri ...

  4. POJ 1014 Dividing(多重背包+二进制优化)

    http://poj.org/problem?id=1014 题意:6个物品,每个物品都有其价值和数量,判断是否能价值平分. 思路: 多重背包.利用二进制来转化成0-1背包求解. #include&l ...

  5. POJ 1014 Dividing (多重可行性背包)

    题意 有分别价值为1,2,3,4,5,6的6种物品,输入6个数字,表示相应价值的物品的数量,问一下能不能将物品分成两份,是两份的总价值相等,其中一个物品不能切开,只能分给其中的某一方,当输入六个0是( ...

  6. POJ 1014 Dividing(多重背包, 倍增优化)

    Q: 倍增优化后, 还是有重复的元素, 怎么办 A: 假定重复的元素比较少, 不用考虑 Description Marsha and Bill own a collection of marbles. ...

  7. POJ 1014 Dividing(入门例题一)

    Time Limit: 1000MS Memory Limit: 10000K Total Submissions: Accepted: Description Marsha and Bill own ...

  8. Hdu 1059 Dividing & Zoj 1149 & poj 1014 Dividing(多重背包)

    多重背包模板- #include <stdio.h> #include <string.h> int a[7]; int f[100005]; int v, k; void Z ...

  9. POJ 1014 Dividing 背包

    二进制优化,事实上是物体的分解问题. 就是比方一个物体有数量限制,比方是13,那么就须要把这个物体分解为1. 2, 4, 6 假设这个物体有数量为25,那么就分解为1, 2, 4. 8. 10 看出规 ...

随机推荐

  1. java 字节流文件复制方法总结

    1.使用字节流每次读写单个字节 public static void main(String[] args) throws IOException { FileInputStream fis = ne ...

  2. underscore.js常用方法整理(慢慢完善)

    整理自Underscore.js (1.8.3) 中文文档,http://www.css88.com/doc/underscore/ 1. extend _.extend() 复制对象中的所有属性到目 ...

  3. Android开发 使用HBuilder的缓存方法

    /* * 中间就可以进行封装操作 * mui就代表mui,owner就代表window的app属性,就是一个传值 */ (function(mui,owner) { /** * 获取当前状态 **/ ...

  4. PHP && ,and ,||,or 的区别

    PHP中的逻辑“与”运算有两种形式:AND 和 &&,同样“或”运算也有OR和||两种形式. 如果是单独两个表达式参加的运算,两种形式的结果完全相同,例如 $a AND $b和$a & ...

  5. 浏览器窗口输入网址后发生的一段事情(http完整请求)

    1.DNS查询得到IP 输入的是域名,需要进行dns解析成IP,大致流程: 如果浏览器有缓存,直接使用浏览器缓存,否则使用本机缓存,再没有的话就是用host 如果本地没有,就向dns域名服务器查询(当 ...

  6. 2014年第五届蓝桥杯B组(C/C++)预赛题目及个人答案(欢迎指正)

    参考:https://blog.csdn.net/qq_30076791/article/details/50573512 第3题: #include<bits/stdc++.h> usi ...

  7. Linux入门进阶第四天——服务管理

    以下均基于CentOS6.3,其中有部分命令已经过时,在CentOS7中不再使用,请注意 [更新]:CentOS7改变: CentOS .0中一个最主要的改变,就是切换到了systemd.它用于替代红 ...

  8. 20155207 2006-2007-2 《Java程序设计》第3周学习总结

    20155207 2006-2007-2 <Java程序设计>第X周学习总结 教材学习内容总结 比较字符串实际字符内容是否相同,不要使用==,要使用equals() 关于类的语法问题 pu ...

  9. Hello World 和 模块分解

    Hello World 和 模块分解 在命令行中编译运行HelloWorld public class HelloWorld { public static void main(String[] ar ...

  10. 优步UBER司机全国各地奖励政策汇总 (4月18日-4月24日)

    滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...