题目链接

http://poj.org/problem?id=1011

题意

输入n根棍子的长度,将这n根棍子组合成若干根长度相同的棍子,求组合后的棍子的最小长度。这题是poj2362的加强版,思路与poj2362相同,只是在2362的基础上添加了剪枝操作,做这题之前先去做poj2362效果最好。

思路

由于棍子越长,组合时的灵活性越差,所以要先从长棍子开始搜索,则首先要将n根棍子从长到短排序,然后从最长的棍子开始dfs。由于棍子最多可以有64根,不剪枝的话肯定会超时。以下是几种剪枝方法:

(1)假设n根棍子中最长的长度为maxLen,n根棍子的长度和为sum,最后求得的结果为len,则len∈[maxLen,sum],且sum%len==0;

(2)由于所有的棍子都降序排序,在组合的过程中若某一棍子不合适,则跳过该棍子后面与其长度相同的所有棍子;

(3)最重要的剪枝:在组合新棍子时,如果添加的第一根棍子stick[i]和剩余的所有棍子都无法组合,则不用继续往下搜索,直接返回(如果继续搜索,到最后stick[i]会被剩下)。

代码

未剪枝代码(超时,dfs部分与poj2362的代码基本相同):

 #include <algorithm>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std; const int INF = <<;
const int N = ;
vector<int> stick;
int visit[N];
int n;
int ans; bool cmp(int a, int b)
{
return a > b; //棍子从长到短排序
} /*
* cur : 当前从第cur根棍子开始尝试组合
* nums : 当前还有nums根新棍子未组合完成
* curLen :当前组合的棍子长度
* len : 要组合的新棍子长度
*/
bool dfs(int cur, int nums, int curLen, int len)
{
if(nums==)
return true; for(int i=cur; i<n; i++)
{
if(visit[i])
continue;
visit[i] = ;
if(curLen+stick[i]<len)
{
if(dfs(cur+, nums, curLen+stick[i], len))
return true;
}
else if(curLen+stick[i]==len)
{
if(dfs(, nums-, , len))
return true;
}
visit[i] = ;
}
return false;
} int main()
{
//freopen("poj1011.txt", "r", stdin);
while(cin>>n && n)
{
int sum = ;
stick.clear();
for(int i=; i<n; i++)
{
int len;
cin>>len;
sum += len;
stick.push_back(len);
} ans = INF;
sort(stick.begin(), stick.end(), cmp);
for(int i=stick[]; i<=sum; i++)
{
if(sum % i != )
continue;
memset(visit, , sizeof(visit));
if(dfs(, sum/i, , i))
{
cout<<i<<endl;
break;
}
}
}
return ;
}

剪枝后代码(AC):

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std; const int INF = <<;
const int N = ;
vector<int> stick;
int visit[N];
int n;
int ans; bool cmp(int a, int b)
{
return a > b; //棍子从长到短排序
} /*
* cur : 当前从第cur根棍子开始尝试组合
* nums : 当前还有nums根新棍子未组合完成
* curLen :当前组合的棍子长度
* len : 要组合的新棍子长度
*/
bool dfs(int cur, int nums, int curLen, int len)
{
if(nums==)
return true; int same = -; //剪枝(2)
for(int i=cur; i<n; i++)
{
if(visit[i] || stick[i]==same)
continue;
visit[i] = ;
if(curLen+stick[i]<len)
{
if(dfs(cur+, nums, curLen+stick[i], len))
return true;
else same = stick[i];
}
else if(curLen+stick[i]==len)
{
if(dfs(, nums-, , len))
return true;
else same = stick[i];
}
visit[i] = ;
if(curLen==) //剪枝(3)
break;
}
return false;
} int main()
{
//freopen("poj1011.txt", "r", stdin);
while(cin>>n && n)
{
int sum = ;
stick.clear();
for(int i=; i<n; i++)
{
int len;
cin>>len;
sum += len;
stick.push_back(len);
} ans = INF;
sort(stick.begin(), stick.end(), cmp);
for(int i=stick[]; i<=sum; i++)
{
if(sum % i != ) //剪枝(1)
continue;
memset(visit, , sizeof(visit));
if(dfs(, sum/i, , i))
{
cout<<i<<endl;
break;
}
}
}
return ;
}

poj1011 Sticks(DFS+剪枝)的更多相关文章

  1. poj1011 Sticks(dfs+剪枝)

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

  2. poj1011(DFS+剪枝)

    题目链接:https://vjudge.net/problem/POJ-1011 题意:给定n(<=64)条木棍的长度(<=50),将这些木棍刚好拼成长度一样的若干条木棍,求拼出的可能的最 ...

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

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

  4. POJ1011 (DFS+剪枝)

    Sticks Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 129606   Accepted: 30388 Descrip ...

  5. POJ 1011 - Sticks DFS+剪枝

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

  6. poj1011 && uva307 DFS + 剪枝

    将木棒从大到小排列,保证每次的选择都是最长可选的木棒. 剪枝: 1 . 如果第 i 根木棒被选择却无法成功拼接,那么后面与其长度相同的也不能选择. 2 . 如果第 cnt + 1 根木棒无法成功拼接, ...

  7. hdu 1145(Sticks) DFS剪枝

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

  8. POJ 1011 Sticks dfs,剪枝 难度:2

    http://poj.org/problem?id=1011 要把所给的集合分成几个集合,每个集合相加之和ans相等,且ans最小,因为这个和ans只在[1,64*50]内,所以可以用dfs一试 首先 ...

  9. DFS(剪枝) POJ 1011 Sticks

    题目传送门 /* 题意:若干小木棍,是由多条相同长度的长木棍分割而成,问最小的原来长木棍的长度: DFS剪枝:剪枝搜索的好题!TLE好几次,终于剪枝完全! 剪枝主要在4和5:4 相同长度的木棍不再搜索 ...

  10. poj 1011 Sticks (DFS+剪枝)

    Sticks Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 127771   Accepted: 29926 Descrip ...

随机推荐

  1. 新式类 VS 经典类

    一.概述 Python中支持多继承,也就是一个子类可以继承多个父类/基类.当一个调用一个自身没有定义的属性时,它是按照何种顺序去父类中寻找的呢?尤其是当众多父类中都包含有同名的属性,这就涉及到新式类 ...

  2. 阳/阴性预测值Positive/negative Predictive Value(推荐AA)

    sklearn实战-乳腺癌细胞数据挖掘(博主亲自录制视频教程) https://study.163.com/course/introduction.htm?courseId=1005269003&am ...

  3. Python之文件操作:os模块

    Python os 模块提供了一个统一的操作系统接口函数 一.对于系统的操作 1.os.name 当前使用平台 其中 ‘nt’ 是 windows,’posix’ 是linux 或者 unix 2.o ...

  4. 往android主项目中添加辅助项目

    一个较大的工程往往需要多个项目组成,便于更好的并行开发和管理,但最后还是要合到一起来发布.那如何往主项目里添加其他辅助项目呢? 通常的做法是将辅助项目打包成jar包,像库一样导入到主项目,但是如果我们 ...

  5. AbstractTransactionalJUnit4SpringContextTests事务回滚

    在单元测试中继承AbstractTransactionalJUnit4SpringContextTests类的 时候,会默认事务回滚. 需要照常执行的话,在执行的测试方法上添加@Rollback(fa ...

  6. 2-sat Codeforces Round #403 (Div. 2, based on Technocup 2017 Finals) D

    http://codeforces.com/contest/782/problem/D 题意: 每个队有两种队名,问有没有满足以下两个条件的命名方法: ①任意两个队的名字不相同. ②若某个队 A 选用 ...

  7. Codeforces Round #191 (Div. 2) B. Hungry Sequence(素数筛选法)

    . Hungry Sequence time limit per test 1 second memory limit per test 256 megabytes input standard in ...

  8. IO流-文件拷贝

    其实文件的拷贝还是文件读取写入的应用,实际是读取此路径上的文件,然后写入到指定路径下的文件. 代码举例: import java.io.*; import java.lang.*; class Tes ...

  9. 【洛谷P2515【HAOI2010】】软件安装

    题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大). 但是 ...

  10. JS中短路运算符&&和||

    在JS函数中我们经常会使用到短路运算符,主要是逻辑与(&&) 和 逻辑或(||) 1.逻辑与 && 的运算方式 var a = 5 && 6; cons ...