POJ 百练1011 STICKS
2016-07-08 18:14
288 查看
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">这题是很经典的一道题。</span>
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">DFS加深搜,重点是让深搜过程加快简化:</span>
1. 搜索顺序。首先依据小棒长度进行由大到小的排序,在每一层搜索时首先将长度大的小棒填入当前原棒中。因为当相对长的小棒占据了原棒的大部分空间后能大大减小可行的搜索状态。
2. 利用排序剪枝。在组合同一支原棒的时候,由于检验小棒是否可用的顺序也是由大到小的,因此在检验到一支小棒可用时,如果当前棒还合填满,可能填入当前棒的小棒的长度也不会比现在填入的这支小棒长。因此,增加一个递归参数NEXT表示可能用于组合当前棒的第一支小棒的数组下标。参数传递时,若当前正好拼成一支原棒,NEXT还原回1,否则将NEXT+1传递给下一层递归。
3. 不进行重复搜索。即在某一状态,若将某一长度的小棒填入当前原棒进行搜索无法最终拼出所有原棒,则对于当前状态,相同长度的小棒也无法填入当前原棒而得到最终解。因此,在记录小棒长度的数组L中增加一指针用于指向下一个与之长度不同的小棒的数组下标,则搜索时,若某一长度小棒不成功,直接尝试下一个与之长度不同的小棒。
4. 首次只尝试最长的小棒。在第一次组合拼接某一根原棒时,首先放入的是当前最长的小棒,并且,如果当前状态可以完成组合,则该小棒必定要放入之后的某一根原棒中,即假设它放在当前原棒中,若放入后搜索失败,则当前状态必定不可能成功,需要回溯。因此,在RES=0时,若第一次搜索失败,则不断续当前状态的其它搜索。
5.如果当前最长的一支可用小棒L'0恰能填满当前正在组合的一支原棒,则如果此次尝试失败,在当前状态下不再做其它尝试,返回上一层递归。因为若当前状态还有可能成功,则当前原棒的剩余长度必定能由另几支更短的小棒L'1、L'2……L'n组合成,且L'0必定出现在之后组合的某支原棒之中,则可以将其中的L'0替换为L'1、L'2……L'n,而将L'0移加当前原棒中,则两种状态等价,因此同样必定失败。因此,在RES+Li=LEN时,若搜索失败,则同样不断续当前状态的其它搜索。
6. 判断所剩可用小棒是否足够拼接当前原棒。累加所有小于当前已经尝试的小棒的长度且未使用的小棒,判断是否足够拼接出当前原棒,若不能,则不继续当前搜索。该剪枝效果不很明显,且计算位置放置不佳可能反而降低率效。
附上代码:
#include <iostream> #include <stdlib.h> using namespace std; int stick[65]; bool visi[65]; int n; void reset(); int cmp(const void* a, const void* b) { return *(int*)b - *(int*)a; } bool ddfs(int a, int b, int num,int s) { //cout << a << ' ' << b << ' ' << num << endl; if (num == 0 && a == 0)return true; if (num == 0 && a != 0)return false; if (num != 0 && a == 0) { a = b; s = 0; } if (a < 0)return false; for (int i = s; i < n; i++) { if (visi[i] == false && stick[i] <= a) { visi[i] = true; if (ddfs(a - stick[i], b, num - 1,i+1))return true; visi[i] = false; if (i == 0)return false; if (a - stick[i] == 0)return false; if (a == b)return false; int tmp = stick[i]; while (i < n - 1 && stick[i + 1] == tmp)i++; } } return false; } void fun() { int sum = 0; for (int i = 0; i < n; i++) { sum += stick[i]; } for (int a = stick[0]; a <= sum; a++) { if (sum%a != 0)continue; reset(); if (ddfs(a, a, n,0)) { cout << a << endl; return; } } } void reset() { for (int i = 0; i < 65; i++) { visi[i] = false; } } int main() { while (cin >> n) { if (n == 0) { break; } reset(); for (int i = 0; i < n; i++) { cin >> stick[i]; } qsort(stick, n, sizeof(int), cmp); fun(); } return 0; }
相关文章推荐
- [置顶] 用递归算法得到Java的树形结构
- 三栏式布局
- Sharepoint 2013 出现The tool was unable to install Application Server Role, Web Server (IIS) Role
- icon右上角显示数字 ios8.0
- Xcode6:The file couldn’t be opened because you don’t have permission to view it
- 腾讯Bugly 最专业的质量跟踪平台(用于跟踪、收集ANR和崩溃)
- 如何在不切换 Activity的同时切换页面布局
- Poj 2406(同1961)
- jQuery 之 隐藏显示与淡入淡出效果(三)
- hdu 1051 Wooden Sticks
- python 参数
- Undefined class constant 'MYSQL_ATTR_INIT_COMMAND'
- enjoy java8 section3
- 将一个从大到小的数组,用以下排序方法排序成从小到大的,()最快。----阿里巴巴2015实习生笔试题
- 存钱问题
- hdu 4527 小明系列故事——玩转十滴水 bfs 解题报告
- 机器学习模型评价(Evaluating Machine Learning Models)-主要概念与陷阱
- 安卓 Manifest 常用属性解析 和 XML 一些属性设置
- php+jq(plupload插件)+ajax多图上传并入库
- 单知识点运用---使用代码编辑页面控件时不同分辨率的自适应