题目链接

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. python编码问题FAQ

    http://note.youdao.com/noteshare?id=2cfb0ac4da042c2550aa3918beda81ec

  2. Tensorboard教程:高维向量可视化

    Tensorflow高维向量可视化 觉得有用的话,欢迎一起讨论相互学习~Follow Me 参考文献 强烈推荐Tensorflow实战Google深度学习框架 实验平台: Tensorflow1.4. ...

  3. [洛谷P2747] [USACO5.4]周游加拿大Canada Tour

    洛谷题目链接:[USACO5.4]周游加拿大Canada Tour 题目描述 你赢得了一场航空公司举办的比赛,奖品是一张加拿大环游机票.旅行在这家航空公司开放的最西边的城市开始,然后一直自西向东旅行, ...

  4. 今日文摘:浅谈 HTML5 的游戏化之路

    如今商业网站中用于广泛的HTML5无限下拉效果已经越来越受到游戏网站的喜爱.各个品牌为了打造专属自己的游戏特色,纷纷推出了模拟HTML5效果的品牌 站,且都起到了相当好的效果.可是从很多方面来说我们对 ...

  5. 用java代码在创建hbase表时指定region的范围

    package com.liveyc.common.utils; import java.util.List; import org.apache.hadoop.hbase.util.Bytes; i ...

  6. 【洛谷 P2764】 最小路径覆盖问题(最大流)

    题目链接 首先有\(n\)条路径,每条路径就是一个点,然后尽量合并,答案就是点数-合并数. 套路拆点,源连入,出连汇,原有的边入出连. 最大流就是最大合并数,第一问解决. 然后怎么输出方案? 我是找到 ...

  7. 2017ACM暑期多校联合训练 - Team 2 1006 HDU 6050 Funny Function (找规律 矩阵快速幂)

    题目链接 Problem Description Function Fx,ysatisfies: For given integers N and M,calculate Fm,1 modulo 1e ...

  8. 42、和为S的两个数字

    一.题目 输入一个递增排序的数组和一个数字S,在数组中查找两个数,是的他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的. 二.解法 import java.util.ArrayLis ...

  9. Ubuntu之镜像iso安装系统

    ubuntu的安装 官网下载iso文件,网址:http://releases.ubuntu.com/16.04.4/, 选择:ubuntu-16.04.4-server-amd64.iso: 下载完毕 ...

  10. netif_start_queue/netif_wake_queue/netif_stop_queue

    在网卡驱动中,内核为发送数据包的流量控制提供了几个主要的函数,用来在驱动程序和内核之间传递流控信息. 主要有4个: 1]netif_start_queue  启动接口传输队列 2]netif_wake ...