Sticks(UVA - 307)【DFS+剪枝】
Sticks(UVA - 307)
算法
DFS+剪枝
1.这道题题意就是说原本有一些等长的木棍,后来把它们切割,切割成一个个最长为50单位长度的小木棍,现在想让你把它们组合成一个个等长的大木棍,要求这个拼接成的大木棍的长度最小。问最小长度是多少。(注意,在接下来的介绍中,将最后的大木棍表述为拼接木棍,小木棍还是叫小木棍)
2.看完这个题,基本思路是从一个小木棍开始找,找到一个未使用的小木棍后拼接,当拼接成的长度是所有小木棍长度和的约数时,就暂时把它定义为拼接木棍的最小长度,然后计算最后需拼接成多少个这个长度的拼接木棍,然后继续寻找,达到这个长度后累加,如果实在没有,重新定义拼接木棍的最下长度。
如果按部就班的按照上面的基本思路做肯定会超时的,而且涉及的点比较多,因为当你所找到的那个最小长度不能够让所有小木棍都能拼接成时,还需继续寻找,这样过于复杂。
那么换个思路,既然是拼接木棍,那么最终拼接木棍的最小长度一定大于等于所有小木棍的最大长度。
那么我们就可以从小木棍的最大长度这个地方开始枚举拼接木棍的长度,这是其中一个可以优化的地方。那什么时候到头呢,拼接木棍的长度最大可以枚举到所有小木棍的长度和,然后就不能再大了。考虑到拼接木棍的长度是小木棍长度和的约数,那么就可以枚举到长度和/2,因为大于长度和/2的部分就没有长度和的约数了(除了长度和本身),这样可以节省一定的时间。当满足条件时,直接退出循环,输出即可,如果循环了所有约数都不满足,直接输出长度和即可。
下面介绍几个剪枝的地方:
- 将存储小木棍长度的数组从大到小排序,这样做的原因是长度大的小木棍相对于长度小的小木棍一定有相对较小的选择,这样在一定情况下节省了时间。
- 枚举拼接木棍的长度时,只考虑约数(小木棍长度和的约数),其余的无需考虑。
- 如果当前木棍与前一个木棍长度相同,并且前一个木棍拼接失败,那么直接跳过当前木棍即可。
- 当目前拼接长度为0时,但尝试了所有的木棍都没有拼接成功,则证明这个拼接木棍的长度无法拼成,return false即可。
3.这道题是一道典型的DFS剪枝题目,涉及的剪枝比较多,稍有一点没涉及到就会TLE。
C++ 代码
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 1000;
int n, units[N];
int sum_length; /*所有小木棍的总长度*/
bool st[N]; /*标记当前小木棍是否被使用*/
int res; /*拼接长度*/
int cnt; /*在拼接长度为res时最终能形成的拼接木棍的个数*/
bool dfs(int len, int k, int i) /*len表示当前的拼接长度,k表示满足res的拼接木棍的个数,i表示下标为i的这个木棍已经考虑完,再枚举时从下一个木棍开始枚举即可*/
{
if(len == res)
{
k++; /*达到拼接长度时,累加拼接木棍的个数*/
len = i = 0;
}
if(k == cnt) return true;
for(int j = i + 1; j < n; j++)
{
if(st[j]) continue; /*当前木棍已经被使用,则不能再使用*/
if(units[j] == units[j-1] && !st[j-1]) continue; /*前一个木棍与它长度相同,但没被使用,那该木棍也无需再验证是否需要使用了*/
if(units[j] + len > res) continue; /*大于拼接长度,则不能考虑*/
st[j] = true;
if(dfs(len + units[j], k, j))
return true;
st[j] = false;
if(len == 0)
return false;
}
return false;
}
int main()
{
while(cin >> n && n)
{
sum_length = 0;
for(int i = 0; i < n; i++)
{
cin >> units[i];
sum_length += units[i];
}
sort(units, units + n, greater<int>());
for(res = units[0]; res <= sum_length / 2; res ++)
{
memset(st, 0, sizeof st);
if(sum_length % res != 0) continue;
cnt = sum_length / res; /*预测的初始木棒个数*/
st[0] = true; /*标记第一个最长的小木棍被使用*/
if(dfs(units[0], 0, 0))
{
cout << res << endl;
break;
}
}
if(res > sum_length / 2) /*大于它时,说明没有可形成的长度,直接输出长度和即可*/
cout << sum_length << endl;
}
}
Sticks(UVA - 307)【DFS+剪枝】的更多相关文章
- DFS(剪枝) POJ 1011 Sticks
题目传送门 /* 题意:若干小木棍,是由多条相同长度的长木棍分割而成,问最小的原来长木棍的长度: DFS剪枝:剪枝搜索的好题!TLE好几次,终于剪枝完全! 剪枝主要在4和5:4 相同长度的木棍不再搜索 ...
- poj 1011 Sticks (DFS+剪枝)
Sticks Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 127771 Accepted: 29926 Descrip ...
- poj 1011 :Sticks (dfs+剪枝)
题意:给出n根小棒的长度stick[i],已知这n根小棒原本由若干根长度相同的长木棒(原棒)分解而来.求出原棒的最小可能长度. 思路:dfs+剪枝.蛮经典的题目,重点在于dfs剪枝的设计.先说先具体的 ...
- *HDU1455 DFS剪枝
Sticks Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Subm ...
- hdu1455 dfs+剪枝
Sticks Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Subm ...
- POJ 3009 DFS+剪枝
POJ3009 DFS+剪枝 原题: Curling 2.0 Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 16280 Acce ...
- poj 1724:ROADS(DFS + 剪枝)
ROADS Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 10777 Accepted: 3961 Descriptio ...
- DFS+剪枝 HDOJ 5323 Solve this interesting problem
题目传送门 /* 题意:告诉一个区间[L,R],问根节点的n是多少 DFS+剪枝:父亲节点有四种情况:[l, r + len],[l, r + len - 1],[l - len, r],[l - l ...
- HDU 5952 Counting Cliques 【DFS+剪枝】 (2016ACM/ICPC亚洲区沈阳站)
Counting Cliques Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) ...
随机推荐
- IOS 提审
关于上架AppStore最后一步的“出口合规信息”.“内容版权”.“广告标识符”的选择 https://blog.csdn.net/ashimar_a/article/details/51745675
- Linux下命令设置别名--alias(同实用于mac)
最近在搞appium自动化脚本编写,过程中经常会使用 uiautomatorviewer这个工具查看UI布局和元素,但是不得不说这个单词太长了.. 如何快速使用,有三个小技巧,分别是: 1.设置好改工 ...
- RTS寻路算法
https://docs.unity3d.com/ScriptReference/Physics.OverlapSphere.html https://www.zhihu.com/question/2 ...
- 支付-微信h5
背景 h5支付分两种 1.浏览器 2.app 浏览器里的h5,最终也会跳转到app. 而app里的h5,本质是公众号.在微信里叫公众号,支付宝叫服务窗. 这里主要讲微信h5. 核心原理 最终目标是下单 ...
- 通俗理解线性回归(Linear Regression)
线性回归, 最简单的机器学习算法, 当你看完这篇文章, 你就会发现, 线性回归是多么的简单. 首先, 什么是线性回归. 简单的说, 就是在坐标系中有很多点, 线性回归的目的就是找到一条线使得这些点都在 ...
- jmeter做简单的压测
一.JMeter概述jmeter除了可以做借口测试外,还可以做压力测试:首先介绍jmeter中各个组件在压力测试中扮演的角色 1)线程(Threads(Users))即虚拟用户,线程组里可设置需要模拟 ...
- smbms系统中引用的js文件出现乱码
问题如下显示: 时间显示出现了乱码,找到显示该时间的js文件,定位问题出现的地方. 解决方案: 改变该文件的编码方式,这里的使用了vscode进行改变js文件的编码方式 步骤如下: 使用vscode打 ...
- 安装paddle的问题,报错Can not find library: libcudnn.so. The process maybe hang.
今天在服务器上安装paddle的GPU版时报错 报错截图如下: 其实报错已经提示的很明显了,就是要添加一个环境变量.但我想到我之前并没有在全局环境下安装cudnn,以为是这个原因.因为之前安装pyto ...
- C#开发PACS医学影像处理系统(十一):Dicom影像挂片协议
通俗点说,挂片协议可以看作整个系统的一个相对复杂一点的配置文件,可以用JSON或XML格式来读取与保存, 另外,可以制作一个独立的exe配置程序来管理这些挂片协议. 假设配置了CT的挂片协议的右键菜单 ...
- Docker跨主机通信(九)
容器网络 在前面的博客中已经详细讲解了几种网络方案: none, host, bridge,user-defined.但是他们只是解决了单个主机间的容器的通信问题,并不能实现多个主机容器之间的通信.本 ...