POJ1011 SticksDFS+剪枝
Posted huanghanqian
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ1011 SticksDFS+剪枝相关的知识,希望对你有一定的参考价值。
题目:
Description
George took sticks of the same length and cut them randomly until all parts became at most 50 units long. Now he wants to return sticks to the original state, but he forgot how many sticks he had originally and how long they were originally. Please help him and design a program which computes the smallest possible original length of those sticks. All lengths expressed in units are integers greater than zero.Input
The input contains blocks of 2 lines. The first line contains the number of sticks parts after cutting, there are at most 64 sticks. The second line contains the lengths of those parts separated by the space. The last line of the file contains zero.Output
The output should contains the smallest possible length of original sticks, one per line.Sample Input
9 5 2 1 5 2 1 5 2 1 4 1 2 3 4 0
Sample Output
6 5思路:
题意:
乔治拿来一组等长的木棒,将它们随机地裁断,使得每一节木棒的长度都不超过50个长度单位。然后他又想把这些木棒恢复到为裁截前的状态,但忘记了木棒的初始长度。请你设计一个程序,帮助乔治计算木棒的可能最小长度。每一节木棒的长度都用大于零的整数表示。
思路:
dfs+剪枝。蛮经典的题目,重点在于dfs剪枝的设计。先说先具体的实现:求出总长度sum和小棒最长的长度max,则原棒可能的长度必在max~sum之间,然后从小到大枚举max~sum之间能被sum整除的长度len,用dfs求出所有的小棒能否拼凑成这个长度,如果可以,第一个len就是答案。
下面就是关键的了,就是这道题dfs的实现和剪枝的设计:
1.以一个小棒为开头,用dfs看看能否把这个小棒拼凑成len长,如果可以,用visit[i]记录下用过的小棒,然后继续以另外一个小棒为开头,以此类推。
2.小棒的长度从大到小排序,这个就不解释了。
3.如果当前最长的小棒不能拼成len长,那么以比它短的开始也一定不能取得全局的成功。因为每一支木棍都要被用到,最长的那根如果现在不行,那么以后也不行。所以直接return,返回前一步。
4.最重要的,就是比如说17,9,9,9,9,8,8,5,2……如果当前最长小棒为17,它与第一个9组合之后dfs发现不能拼成len,那么17就不用和后面所有的9组合了,而直接和8开始组合。这个剪枝直接从TLE到16MS,很强大。
代码:
#include <iostream>
#include <algorithm>
using namespace std;
bool isEnd=false;
int len=-1;
int a[64];
int visit[64]=0;
int num;
void dfs(int used_num,int now_len,int now_index) //used为当前已被用过的小棒数,now_index为当前要处理的小棒。
if(isEnd==true)
return;
if(now_len==len) //当前长度为len,即又拼凑成了一根原棒。
if(used_num==num) //完成的标志:所有的num根小棒都有拼到了。
isEnd=true;
else
dfs(used_num,0,0);
return;
if(now_len==0) //当前长度为0,寻找下一个当前最长小棒。
while(visit[now_index]==1) now_index++; //寻找第一个当前最长小棒。
visit[now_index]=1;
dfs(used_num+1,a[now_index],now_index+1);
visit[now_index]=0;
else
for(int i=now_index;i<num;i++)
if(visit[i]==0&&now_len+a[i]<=len)
if((visit[i-1]==0&&a[i]==a[i-1])) //不重复搜索:最重要的剪枝。
continue;
visit[i]=1;
dfs(used_num+1,now_len+a[i],i+1);
visit[i]=0;
bool compare(int a,int b)
return a>b; //降序排列
int main()
while(cin>>num)
if(num==0)
break;
isEnd=false;
int sum=0;
int max=0;
for(int i=0;i<num;i++)
cin>>a[i];
sum+=a[i];
if(a[i]>max)
max=a[i];
sort(a,a+num,compare); //从大到小排序。
for(len=max;len<sum;len++)
if(sum%len!=0)
continue;
else //枚举能被sum整除的长度。
memset(visit,0,sizeof(visit));
dfs(0,0,0);
if(isEnd==true)
break;
cout<<len<<endl;
return 0;
下面学习一下
sort函数的用法:
#include <algorithm>
void sort( iterator start, iterator end );
void sort( iterator start, iterator end, StrictWeakOrdering compare );
sort 是对给定区间所有元素进行排序
第一个只需要传递你要排序的串(整形数组等都行)的头指针(数组第一个元素的指针)与数组最后元素的下一个位置。
第二个前面两个参数同第一,但第三个参数是传递一个你定义用于排序的函数。this
举例:
bool compare(int a,int b)
return a<b; //升序排列,如果改为return a>b,则为降序
int _tmain(int argc, _TCHAR* argv[])
int a[20]=2,4,1,23,5,76,0,43,24,65,i;
for(i=0;i<20;i++)
cout<<a[i]<<endl;
sort(a,a+20,compare);
for(i=0;i<20;i++)
cout<<a[i]<<endl;
return 0;
以上是关于POJ1011 SticksDFS+剪枝的主要内容,如果未能解决你的问题,请参考以下文章