题目大意:

  George有许多长度相同的木棍,随机的将这些木棍砍成小木条,每个小木条的长度都是整数单位(长度区间[1, 50])。现在George又想把这些小木棒拼接成原始的状态,但是他忘记了原来他有多少根木棍,也忘记了木棍的长度。现在请你编写一个程序,找到最短的原始的木棍长度。

输入:

  每个测试案例包含两行,第一行表示小木条的总个数(最多64根小木条),第二行表示每个小木条的长度,用空格分开。当第一行输入为零的时候表示程序结束。

输出:

  对于每个测试案例输出最短的木棍长度。

解题思路:

  用搜索算法去解决问题需要知道搜索的区间和剪枝条件,现在木棍长度未知,木棍个数未知,对于我们搜索是不利的。需要从已知条件推导到一个可以搜索的区间,然后再仔细思考如何剪枝来减少时间复杂度。

  小木条是从木棍上砍下来的 => 木棍长度的下限:最长的小木条长度(part_max)

  小木条的个数和长度已知    => 木棍长度的上限:所有小木条长度之和(part_sum)

  确定搜索区间:木棍长度(stick_len) ∈ [part_max, part_sum]  并且 stick_len ∈ 整数

  确定了stick_len => 确定了木棍的个数(stick_num)

  剪枝1:当确定一个stick_len时候,那么这个stick_len要能整除part_sum,否则不能组成整数stick_num

  剪枝2:见AC代码分析

  剪枝3:见AC代码分析

  

AC代码:

 // 19472897    2017 - 01 - 02 12:45 : 00    Accepted    1455    15MS    1724K    2328 B    C++    潮州牛肉丸
#include <stdio.h>
#include <algorithm>
#include <functional> int n; // the number of parts
int part[]; // the parts at most 64
int visit[]; // mark the situation of already used parts
int part_sum = ; // 所有小木条的长度之和
int stick_num = ; // 木棍的个数
int stick_len = ; // 木棍的长度 void init()
{
part_sum = ;
stick_num = ;
memset(part, , sizeof(part));
memset(visit, , sizeof(visit));
} // count:已经拼接好的木棍数,len:正在拼接的木棍长度,index:上一次搜索下标位置
bool dfs(int count, int len, int index)
{
if (stick_num == count)
return true; for (int i = index + ; i < n; ++i)
{
if (true == visit[i])
continue;
if (len + part[i] == stick_len)
{
visit[i] = true;
if (true == dfs(count + , , -))
return true;
visit[i] = false;
return false;
}
else if (len + part[i] < stick_len)
{
visit[i] = true;
if (true == dfs(count, len + part[i], i))
return true;
visit[i] = false; /* 已知条件:
1、stick的长度(stick_num)和个数(stick_num)
2、dfs已经返回false
*/ /* 剪枝2:当dfs返回false,len等于0的时候,stick的长度不是题目的正确结果,
后面的搜索无意义,直接返回false。 根据原则:如果当前搜索用的stick长度是题目的正确结果,那么所有的part都一定要被用上。
然而拼接一根新stick的时候(即len的值为0,表示当前正在拼接一根新stick),选取
的第一根part无论如何都能被用上,只是后面的part去配合第一根part完成一根stick,
如果在用第一根part的时候,dfs任然返回false,表示这个part不能被用上拼接stick。
与原则相违背。
*/
if ( == len)
return false; /* 剪枝3:
当前状态:dfs返回false,说明part[i]这根木条在当前count,len状态不可用,
接下来搜索的part[i+1]如果与之前的part[i]长度相同也一定不可用,注意我们是把part按降序排序过的*/
while (i < n && part[i] == part[i + ])
++i;
}
}
return false;
} int main(void)
{
while (scanf("%d", &n) != EOF && != n)
{
init();
for (int i = ; i < n; ++i)
{
scanf("%d", &part[i]);
part_sum += part[i]; //记录所有小木条长度之和
} std::sort(part, part + n, std::greater<int>()); // 按照降序排序 // stick的可能长度区间:[最长的小木条长度,所有小木条长度之和]
for (stick_len = part[]; stick_len < part_sum; ++stick_len)
{
if ( == part_sum % stick_len) //剪枝1:木棍的长度一定要能整除所有小木条长度之和
{
stick_num = part_sum / stick_len; // 得到stick的个数
if (true == dfs(, , -))
break;
}
} printf("%d\n", stick_len);
}
return ;
}

hdu 1455 Sticks(dfs+剪枝)的更多相关文章

  1. HDU 1455 Sticks(经典剪枝)

    Sticks Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Sub ...

  2. hdu 1145(Sticks) DFS剪枝

    Sticks Problem Description George took sticks of the same length and cut them randomly until all par ...

  3. hdu 1455 Sticks

    Sticks Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Statu ...

  4. poj 1011 :Sticks (dfs+剪枝)

    题意:给出n根小棒的长度stick[i],已知这n根小棒原本由若干根长度相同的长木棒(原棒)分解而来.求出原棒的最小可能长度. 思路:dfs+剪枝.蛮经典的题目,重点在于dfs剪枝的设计.先说先具体的 ...

  5. poj1011 Sticks(dfs+剪枝)

    Sticks Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 110416   Accepted: 25331 Descrip ...

  6. hdu - 1072(dfs剪枝或bfs)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1072 思路:深搜每一个节点,并且进行剪枝,记录每一步上一次的s1,s2:如果之前走过的时间小于这一次, ...

  7. POJ 1011 - Sticks DFS+剪枝

    POJ 1011 - Sticks 题意:    一把等长的木段被随机砍成 n 条小木条    已知他们各自的长度,问原来这些木段可能的最小长度是多少 分析:    1. 该长度必能被总长整除    ...

  8. HDU 1175 连连看 (DFS+剪枝)

    <题目链接> 题目大意:在一个棋盘上给定一个起点和终点,判断这两点是否能通过连线连起来,规定这个连线不能穿过其它的棋子,并且连线转弯不能超过2次. 解题分析:就是DFS从起点开始搜索,只不 ...

  9. hdu 1044(bfs+dfs+剪枝)

    Collect More Jewels Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Othe ...

随机推荐

  1. 使用appium进行ios测试,启动inspector时遇到的问题(一)

    最近在公司,让做ios的自动化测试,因为以前做过android的自动化测试,用的也是appium,觉得没什么,结果一开始在搭建环境就遇到了很多的问题,现在将我遇到的问题,以及解决方法,给大家分享出来. ...

  2. c++学习一:指针基础

    1.指针优势,当数据量比较大时,通过指针直接访问数据量所在内存.处理更 加复杂的数据结构.例如:链表.二叉树.图等.2.指针本质是一种表示内存地址的数据类型,它和整型int和浮点数float一样 只是 ...

  3. Android自动化学习笔记:获取APK包名的几种方法

    ---------------------------------------------------------------------------------------------------- ...

  4. redhat7下配置tomcat7,更改端口8080后无法访问页面

    搞了一下午,居然是防火墙的事情,redhat7设置方法如下 sudo firewall-cmd --add-port=8081/tcp

  5. Find out files transfered via Bluetooth

    The case was about business secret and forensic guy did a physical acquisition from a smart phone. H ...

  6. IP地址划分

    对于32位的IPV4地址来说,有5中IP地址类型 A类IP地址第一个字节是网络地址,后三个字节是主机地址,且最高位以0开头. 0000001  00000000   00000000 00000001 ...

  7. 监控平台项目之CSS总结——基于angularjs、bootstrap、jquery等框架

    1.新加一个类名,实现切换页面主题 在需要变色的标签处,添加该类名,即可实现最简化切换页面主题. HTML: <section ui-view=""> </sec ...

  8. Math类中的BigDecimal

    如果我们编译运行下面这个程序会看到什么? public class Test {    public static void main(String args[]) {                 ...

  9. Random Javascript code snippets

    MollyPages.org"You were wrong case.To live here is to live." Home Pages / Database / Forms ...

  10. bootstrap--小李子demo

    最近忙啊...看到各位冬鞋都在认真写博客,认真敲代码,认真工作,总觉得自己时间太少,总觉得时间不够,老了...... 进正题: 上次不知从哪里(忘了)下载了bootstrap的一些使用小demo,以后 ...