深搜的剪枝技巧(三)——Sticks(可行性剪枝、上下界剪枝、最优性剪枝)
小木棍(最优性剪枝、可行性剪枝)
一、问题描述
- 乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,已知每段的长都不超过 50 。现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度。给出每段小木棍的长度,编程帮他找出原始最短木棍的可能长度
二、输入格式
- 第一行为一个整合 N,表示砍过以后的小木棍总数,其中 \(N\leq 60\)
- 第二行为 N 个用空格隔开的整数,表示 N 根小木棍的长度
三、输出格式
- 输出文件仅一行,表示要求的原始最短木棍的可能长度
四、样例输入
9
5 2 1 5 2 1 5 2 1
五、样例输出
6
六、思路分析
- 利用搜索枚举所有可能出现的情况 every_len,从 1 开始,枚举到它们所有的和(最坏的情况,只有一根),枚举的状态是当前木棍数 now,当前已获得木棍长度 now_len,当前要处理的序号 now_code,递归从 now_len 开始,以 now_len 是否为 0 为标志,如果为 0,则需要传入一个新的 now_len(判断下一个数),如果不为 0,若等于 every_len,说明找到一组满足条件的数,传入一个新的 now,并将 now_len 置为 0,如果不等于 every_len,说明还未达到 every_len,那么需要加数字,再进行判断,通过 now_code 传递下标,如果下标没变,说明这个 every_len 不合适,退出递归,直至判断完所有 every_len。
七、剪枝分析
- 上下界剪枝——上界为所有小木棍的和,下界为最长的小木棍,即原木棍长度一定大于最长的木棍
- 优化搜索顺序——对原数据排序,避免重复情况
- 最优性剪枝——原木棍长度一定可以被所有木棍长度之和整除,不然无法拼出整数根
- 可行性剪枝 1——相同长度的木棍不需要搜索多次,因此有相同长度的木棍,就不用再次进入递归
- 可行性剪枝 2——找到结果后,立马返回上层递归处
- 可行性剪枝 3——搜索到的木棍组成的大于 every_len ,停止搜索
八、代码
#include<iostream>
#include<cstdlib>
#include <cstring>
#define MAX_N 64
using namespace std;
int n,sum_len,len[MAX_N+1],every_len,num;
bool used[MAX_N+1];
bool legal;
int compare(const void* e1,const void* e2)
{
    return *(int *)e2-*(int *)e1;
}
void dfs(int now,int now_len,int now_code)
{
    if(legal)
        return;
    if(now_len == every_len)     //可行性剪枝 2
    {
        dfs(now+1,0,0);
        return;
    }
    if(now == num)
    {
        legal = true;
        return;
    }
    if(now_len == 0)
    {
        for(int i = 1; i <= n; i++)
            if(!used[i])
            {
                used[i] = true;
                dfs(now,len[i],i+1);
                used[i] = false;
                return;
            }
    }
    int j=0;
    for(int i = now_code;i <= n;i++)
    {
        if(now_len+len[i] <= every_len && !used[i] && (len[i] != len[j]))   //可行性剪枝 3,可行性剪枝 1
        {
            j = i;
            used[i] = true;
            dfs(now,now_len+len[i],i+1);
            used[i] = false;
        }
    }
    return;
}
int main()
{
    ios::sync_with_stdio(false);
    while(cin >> n && n)
    {
        sum_len = 0;
        for(int i = 1;i <= n; i++)
        {
            cin >> len[i];
            sum_len += len[i];
        }
        qsort(len+1,n,sizeof(int),compare);      //优化搜索顺序
        memset(used,false,sizeof(bool));
        for(every_len = len[1];every_len <= sum_len;every_len++)     //上下界剪枝
            if(sum_len % every_len == 0)    //最优性剪枝
            {
                legal = false;
                num = sum_len/every_len;
                dfs(1,0,1);
                if(legal)
                    break;
            }
        cout<<every_len<<endl;
    }
    return 0;
}
深搜的剪枝技巧(三)——Sticks(可行性剪枝、上下界剪枝、最优性剪枝)的更多相关文章
- ACM 海贼王之伟大航路(深搜剪枝)
		"我是要成为海贼王的男人!" 路飞他们伟大航路行程的起点是罗格镇,终点是拉夫德鲁(那里藏匿着"唯一的大秘宝"--ONE PIECE).而航程中间,则是各式各样的 ... 
- 一本通例题埃及分数—题解&&深搜的剪枝技巧总结
		一.简述: 众所周知,深搜(深度优先搜索)的时间复杂度在不加任何优化的情况下是非常慢的,一般都是指数级别的时间复杂度,在题目严格的时间限制下难以通过.所以大多数搜索算法都需要优化.形象地看,搜索的优化 ... 
- 【深搜加剪枝】【HDU1455】【Sticks】
		题目大意:有一堆木棍 由几个相同长的木棍截出来的,求那几个相同长的木棍最短能有多短? 深搜+剪枝 具体看代码 #include <cstdio> #include <cstdlib& ... 
- poj1190 生日蛋糕(深搜+剪枝)
		题目链接:poj1190 生日蛋糕 解题思路: 深搜,枚举:每一层可能的高度和半径 确定搜索范围:底层蛋糕的最大可能半径和最大可能高度 搜索顺序:从底层往上搭蛋糕,在同一层尝试时,半径和高度都是从大到 ... 
- 一本通例题-生日蛋糕——题解<超强深搜剪枝,从无限到有限>
		题目传送 显然是道深搜题.由于蛋糕上表面在最底层的半径确认后就确认了,所以搜索时的面积着重看侧面积. 找维度/搜索面临状态/对象:当前体积v,当前外表面面积s,各层的半径r[],各层的高度h[]. 可 ... 
- 【笔记】「pj复习」深搜——简单剪枝
		深搜--简单剪枝 说在最前面: 因为马上要 NOIP2020 了,所以菜鸡开始了复习qwq. pj 组 T1 ,T2 肯定要拿到满分的,然后 T3 , T4 拿部分分, T3 拿部分分最常见的做法就是 ... 
- Hdu3812-Sea Sky(深搜+剪枝)
		Sea and Sky are the most favorite things of iSea, even when he was a small child. Suzi once wrote: ... 
- UVA 10160 Servicing Stations(深搜 + 剪枝)
		Problem D: Servicing stations A company offers personal computers for sale in N towns (3 <= N < ... 
- hdu 1518 Square(深搜+剪枝)
		题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1518 题目大意:根据题目所给的几条边,来判断是否能构成正方形,一个很好的深搜应用,注意剪枝,以防超时! ... 
随机推荐
- spring Boot 学习(五、Spring Boot与安全)
			一.安全Spring Security是针对Spring项目的安全框架,也是Spring Boot底层安全模 块默认的技术选型.他可以实现强大的web安全控制.对于安全控制,我们仅 需引入spring ... 
- C语言-MySQL单表查询(vs2013环境)
			一.首先配置项目属性: 1.打开mysql的安装路径,找到include文件夹和lib文件夹 如图: 2.在vs2013中, 打开项目–> 属性 –>VC++目录 如图: 把将nclude ... 
- python基础知识(七)---数据类型补充、"雷区"、编码
			数据类型补充."雷区".编码 1.数据类型补充 str: #字符串数据类型补充 s1=str(123) #常用于类型转换 print(s1) #capitalize()首字母大写 ... 
- 将windows共享文件夹挂载到Linux
			今天想用docker部署下 .net core的 服务,需要把代码文件从windows传到linux,以前一直都是拖拽的,这次安装的系统没有图形界面, 所以到网上找到了下面的这种方法,将共享文件夹挂载 ... 
- 使用sudo进行Linux权限升级技巧
			0x00 前言 在我们之前的文章中,我们讨论了如何使用SUID二进制文件和/etc/passwd 文件的Linux权限提升技巧,今天我们发布了另一种“使用Sudoers文件进行Linux权限提示技巧” ... 
- [LeetCode] 543. 二叉树的直径 ☆(递归、数最大深度)
			描述 给定一棵二叉树,你需要计算它的直径长度.一棵二叉树的直径长度是任意两个结点路径长度中的最大值.这条路径可能穿过根结点. 示例 :给定二叉树 1 / \ 2 3 / \ 4 5 返回 3, 它的长 ... 
- AIX安装单实例11gR2 GRID+DB
			AIX安装单实例11gR2 GRID+DB 一.1 BLOG文档结构图 一.2 前言部分 一.2.1 导读和注意事项 各位技术爱好者,看完本文后,你可以掌握如下的技能,也可以 ... 
- 基于cmake编译glew
			cmake已经成为了C/C++开源项目的主流构建工具.glew也提供了cmake的脚本,但用cmake编译glew容易采坑:glew的github上的代码,无论是master分支还是glew-2.1. ... 
- Python的插件化开发概述
			Python的插件化开发概述 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.插件化开发 动态导入: 运行时,根据用户需求(提供字符串),找到模块的资源动态加载起来. 1> ... 
- python写一些简单的tcp服务器和客户端
			代码贴上,做个记录 TcpClient # -*- coding:utf-8 -*- import socket target_host = "127.0.0.1" #服务器端地址 ... 
