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) ...
随机推荐
- Stone(思维)
链接:https://ac.nowcoder.com/acm/contest/893/D来源:牛客网 题目描述 有n堆石子排成一排,第i堆石子有aiai个石子. 每次,你可以选择任意相邻的两堆石子进行 ...
- 你不知道的JavaScript笔记----对象
对象: 1.定义对象属性 属性描述符(也称为:数据描述符) Object.defineProperty(Object,PropertyName,{ value: 6, writable: true, ...
- 15 自定义分页pagination全局组件
1.Pagination.vue <template> <el-pagination @size-change="handleSizeChange" @curre ...
- 剑指 Offer 45. 把数组排成最小的数
题目描述 输入一个非负整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个. 示例 1: 输入: [10,2] 输出: "102" 示例 2: 输入: ...
- Ajxax技术-1
1.什么是Ajax Ajax: Asynchronous javascript and xml (异步javascript和xml). ==Ajax并不是一种新技术,而是已有技术的集合.JavaScr ...
- Myeclipse 连接数据库(jdbc)
1.找到DataBase Explorer,如下图所示: 2.点击下图红框内图标,new 3.进入下图界面 如果是JDBC驱动按下图配置: driver name自己起 url一定要注意:jdbc:m ...
- UEFI+MBR
前言 传统情况下装系统的两种方案bios + mbr 或 uef i+ gpt but一直有一个疑问! 是否可以使用uefi + mbr 名词解释 硬盘格式 MBR分区:全称"Master ...
- Java多线程--两个线程同时对一个人的年龄进行增加和修改
public class Thread_A extends Thread { Human human; public Thread_A(String name, Human human) { supe ...
- Odoo10.0中的工作流
Odoo10.0中可以通过两种方式来实现工作流(workflow) 一种的官网API中给出的方式,链接:https://www.odoo.com/documentation/10.0/referenc ...
- Linux:安装禅道
一.准备工作 禅道安装包ZenTaoPMS.8.1.3.zbox_64.gz,上传至服务器:rz命令 解压到指定目录 tar -zxvf ZenTaoPMS.8.1.3.zbox_64.gz -C ...