题目大意:

  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. pip China

    建个文件 ~/.pip/pip.conf, 内容如下 [global] index-url = http://b.pypi.python.org/simple [install] use-mirror ...

  2. delphi.指针.应用

    注:初稿...有点乱,可能增删改... 因为指针应用,感觉不好写,请大家指出错误,谢谢. 注意: 本文着重点讲的是指针的各类型的应用或使用,而不是说这种方法不应该+不安全+危险+不提倡使用. 其它:本 ...

  3. Linux RPM、TAR包管理

    一.RPM软件包命令的使用 RPM主要有5种基本操作模式:安装.卸载.刷新.升级及查询.下面分别介绍. 1.安装软件包 命令语法: rpm -ivh [RPM包文件名称] 命令中各参数的含义如下: - ...

  4. msChart组件安装与编程

    首先下载mschart.ocx文件,至于它所依赖的.net环境,网上有很多,本人下载的插件给出链接,http://www.cr173.com/soft/47300.html而它所依赖的环境可以从我的云 ...

  5. oracle 查询执行过的SQL语句

    SELECT * FROM v$sqlarea t WHERE t.FIRST_LOAD_TIME between '2016-12-23/16:03:00' and '2016-12-23/16:0 ...

  6. PHP命名空间的作用、为什么使用命名空间?

    命名空间一个最明确的目的就是解决重名问题,PHP中不允许两个函数或者类出现相同的名字,否则会产生一个致命的错误.这种情况下只要避免命名重复就可以解决,最常见的一种做法是约定一个前缀. 举个栗子:项目中 ...

  7. MFC 自绘按钮 消息响应

    单检测到按下消息时,发送一个消息 m_pParent->PostMessage(WM_COMMAND, IDC_BUTTON1); 然后再在消息映射里建立映射. ON_COMMAND(IDC_B ...

  8. Winform Textbox MultiLine和WordWrap属性的使用

    突然用到,有些不明白,零乱记录下: 1.MultiLine属性为True时,Dock属性Fill值才能达到所需效果 2.MultiLine属性为False时,WordWrap属性也是无效果的,同1,T ...

  9. Linux 文件与目录管理

    Linux 文件与目录管理 我们知道Linux的目录结构为树状结构,最顶级的目录为根目录 /. 其他目录通过挂载可以将它们添加到树中,通过解除挂载可以移除它们. 在开始本教程前我们需要先知道什么是绝对 ...

  10. Session操作

    存储API localStorage和sessionStorage通常被当做普通的JavaScript对象使用:通过设置属性来存储字符串值,查询该属性来读取该值.除此之外,这两个对象还提供了更加正式的 ...