题目描述

乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过 50 50 50。

现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度。

给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度。

输入格式

共二行。

第一行为一个单独的整数N表示砍过以后的小木棍的总数,其中 N ≤ 65 N≤65 N≤65

(管理员注:要把超过 50 50 50的长度自觉过滤掉,坑了很多人了!)

第二行为 N N N个用空个隔开的正整数,表示 N N N根小木棍的长度。

输出格式

一个数,表示要求的原始木棍的最小可能长度

思路

最近二分法写的有点多,看到题就想二分搜索,但是如何更新 l , r l,r l,r的值是一个问题,因为目标长度是否可以作为最小原始长度这个条件不单调,比如如果切割后的总长是40,那么11肯定不可能是最小原始长度,但是10和20却都有可能,所以二分法不好。我们只能依次遍历,但这时候又会出现问题,对某一个长度,要判断他能否作为最小原始长度我们会想到大法师(DFS)不断回溯,这个过程一定会TLE可能会TLE,必须剪枝 剪枝再剪枝。

大法师

先来看看大法师应该怎么写,效率比较高。给定一个目标长度 t a r g e t target target,我们通过木棍的总长 t o t tot tot可以计算出需要把它还原成 t o t / t a r g e t = n u m tot/target=num tot/target=num个木棍,假设一个参数 s u m sum sum表示目前已经凑了多长的木棍,初始化为0,统计出切割后的最长木棍的长度 m a x n maxn maxn。对大法师而言,

  • 什么时候截止?所有木棍都进行了还原,当前还需要还原的木棍数目为0时,就可以成功返回。
if (num == 0) return true;//没有木棍了,所有木棍都凑完了
  • 如何进行状态的更新?(i)当前已经凑出 t a r g e t target target长的木棍的话,就可以开始拼凑下一个木棍,即下图。(ii)如果还没有拼凑成功,那我们需要选一根木棍继续拼凑,这个木棍的长度加上当前拼凑的长度一定会小于 t a r g e t target target,这里需要回溯,尝试各种各样的木棍。 c n t [ i ] cnt[i] cnt[i]记录长度为 i i i的木棍出现的次数。现在没讲的都是剪枝操作了,后面再讲。
 if (sum == target) return dfs(num - 1, 0, target, maxx);//这里的参数始终是maxxfor (ll i = maxn; i >= minn; i--) {//(2) 从大到小遍历,if (cnt[i] && sum + i <= target) {cnt[i]--;if (dfs(num, sum + i, target, i)) return true;//(3) 这里最后一个参数是icnt[i]++;//回溯if (sum == 0 || sum + i == target)//(4)break;}}return false;

如何剪枝?

  1. 从最长的木棍的长度开始,枚举原先每根木棍的可能长度,一直到(剪枝一:) 总长度的一半(如果原先木棍的数量不为1,则原先木棍的长度必然小于所有木棍总长度的一半)。(小贴士:如果枚举完后,仍然没有输出答案,则直接输出总长度即可)(因为如果一直到总长度的一半都没有解,则说明原先的木棍就只有一根而已)
  2. 我们需要对这些进来的数据排个序,大的在前小的在后。为什么呢?因为打怪的时候不都是先开大再A一下补刀的吗排好序的数组更方便优化2的操作,而且小的木棒灵活性更强,放在前面可以组合出非常多没用的结果,你想想看大木棒都被你扔一边去了,小木棍给用完了,到时候怎么拼成长度一样的木棍?
  3. 经过一番哲学分析我们可以发现,拼好的木棍的长度肯定是所有砍成的小木棍长度之和的因数。也就是说,在遍历所有的原长时,应该判断木棍总长是否可以整除原长。
  4. 在拼一根原木棍的时候注意,一定要从比上一根拼进此原木棍的木棍长度更小的木棍开始尝试拼接。你想想你曾经尝试过将一根大木棍拼进去发现拼不了,选了一个较小的,现在叫你选下一根,你却又选了那根大木棍……(警告:当你新开始拼一根新的原木棒时请从头开始尝试拼接)
  5. 还有一个难想却特别特别重要的优化:若某组拼接不成立,且此时 已拼接的长度为0 或 当前已拼接的长度与刚才枚举的长度之和为最终枚举的答案 时,则可直接跳出循环,因为此时继续枚举其它更小的值时,显然可能情况更少,且同样凑不完。比如我选这里刚开始进行搜索,目标长度为5,木棍 5 , 5 , 5 , 2 , 2 , 2 , 1 , 1 , 1 5,5,5,2,2,2,1,1,1 5,5,5,2,2,2,1,1,1,我先选了 5 5 5,最后没有拼凑成功,返回后这里 s u m = 0 sum=0 sum=0,那么选 2 2 2从头开始还有用吗?思考ing
#include<iostream>
#include<cmath>
#include<iomanip>
#include<string.h>
#include<vector>
#include<map>
#include<queue>
#include<algorithm>
using namespace std;#define MAX 70
#define inf 1e9
#define ll int
#define p pair<ll, ll>ll n, s[MAX], tot = 0, minn = inf, maxx = 0, tmp, cnt[MAX];
bool cmp(ll a, ll b) { return a > b; }//num:木棍的总数目 sum:目前凑了多长 target:目标长度 maxn:最长木棍
bool dfs(ll num, ll sum, ll target, ll maxn) {if (num == 0) return true;//没有木棍了,所有木棍都凑完了if (sum == target) return dfs(num - 1, 0, target, maxx);//这里的参数始终是maxxfor (ll i = maxn; i >= minn; i--) {//(2) 从大到小遍历,if (cnt[i] && sum + i <= target) {cnt[i]--;if (dfs(num, sum + i, target, i)) return true;//(3) 这里最后一个参数是icnt[i]++;//回溯if (sum == 0 || sum + i == target)//(4)break;}}return false;
}
int main() {while (cin >> n && n) {tot = 0, minn = MAX, maxx = 0; memset(cnt, 0, sizeof(cnt));for (ll i = 0; i < n; i++){cin >> s[i];if (s[i] <= 50) {tot += s[i]; cnt[s[i]]++;minn = min(minn, s[i]); maxx = max(maxx, s[i]);}}sort(s, s + n, cmp);//(1)ll l = maxx, r = tot;for (ll i = maxx; i <= tot; i++) {//从小到大依次判断他们能否作为最小长度if (tot%i == 0 && dfs(tot / i, 0, i, maxx))//不能整除肯定不行的啦{cout << i << endl; break;}}}
}

Poj 1011:sticks通俗易懂 大法师+强力剪枝相关推荐

  1. POJ - 1011 Sticks(dfs+剪枝)(好题!!)

    题目链接:点击查看 题目大意:乔治拿来一组等长的木棍,将他们随机砍断,使得每一节木棍的长度都不超过50个单位长度,然后他又想将这些木棍恢复成砍断之前的状态,但他忘记了初始时有多少根木棍以及木棍的初始长 ...

  2. POJ 1011 Sticks

    POJ_1011 做完这个题目,让我不仅学到了一些别人剪枝的策略,更重要的是让我意识到了在搜索中剪枝的重要性. 所谓剪枝,其实就是对程序的优化,尽可能地避免程序执行无用的操作.就这个题目而言,程序的优 ...

  3. poj 1011 Sticks 搜索

    发一道老早写的题. 1 #include<iostream> 2 #include <algorithm> 3 using namespace std; 4 int a[65] ...

  4. Poj 1011 UVA - 307 Sticks

    牛客网 poj 1011 题目: George took sticks of the same length and cut them randomly until all parts became ...

  5. POJ 1190 生日蛋糕 【DFS + 极限剪枝】

    题目传送门:http://poj.org/problem?id=1190 参考剪枝:https://blog.csdn.net/nvfumayx/article/details/6653111 生日蛋 ...

  6. Sticks(经典深搜+剪枝)

    #include <iostream> #include <algorithm> using namespace std;//total能组成的木棒的组数,l:组成的木棒的长度 ...

  7. 搜索 + 剪枝 --- POJ 1101 : Sticks

    Sticks Problem's Link:   http://poj.org/problem?id=1011 Mean: http://poj.org/problem?id=1011&lan ...

  8. 木棒,POJ(1011)

    题目链接:http://poj.org/problem?id=1011 解题报告: #include <cstdio> #include <cstring> #include ...

  9. 1011 Sticks

    1204 Sticks 时间限制:1000MS  内存限制:10000K 提交次数:0 通过次数:0 题型: 外判编程题   语言: 无限制 Description George took stick ...

最新文章

  1. tomcat启动出现闪退_(转)Tomcat 启动后 “闪退”
  2. HTML下拉菜单去掉点,jQuery点击页面其他部分隐藏下拉菜单功能
  3. ubuntu 12.10 笔记
  4. Tomcat乱码解决
  5. linux配置服务器超时退出,Linux下实现不活动用户登录超时后自动登出
  6. MyBatis中的一级缓存和二级缓存介绍
  7. careercup-链表 2.7
  8. SQLite判断表是否存在
  9. LaTeX数学符号大全
  10. 重编译 microsip 和 pjsip 支持 mp3 录音
  11. 马哥教育42期第三周作业
  12. 分享一个整理了很多Android开发工具类的链接AndroidUtilCode
  13. 使用C++让鼠标指针抖动
  14. NCRE-嵌入式系统开发工程师-操作系统知识整理
  15. 为MacTex配置Ctex环境
  16. mac os php Phalcon拓展
  17. Harray Potter and the Sorcerer's Stone
  18. 进度条制作-CSS动画
  19. 警察抓到ABCD四个小偷C语言,警察抓小偷游戏作文450字
  20. 大漠插件ocr多选字库_易语言大漠单线程模块制作设置字库及Ocr识别字符串

热门文章

  1. Flutter Transform变形
  2. [每日一题] Hello, 2020!
  3. Cisco Packet Tracer的安装与汉化(一条龙服务教程)
  4. finally在python中是什么意思_“finally”总是在Python中执行吗?
  5. LeetCode简单题之统计数组中峰和谷的数量
  6. 在线报修管理系统是什么?在线报修系统有什么优势?
  7. 《实战AI低代码》:普元智能化低代码开发平台发布,结合专有模型大幅提升软件生产力
  8. 软件架构模式之分层模式
  9. 深入学习Lua知识点整理
  10. c语言中的beep函数,c++ Beep函数