题目:
Description
Input
Output
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
#include
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;ib; //降序排列
}
int main(){
while(cin>>num){
if(num==0)
break;
isEnd=false;
int sum=0;
int max=0;
for(int i=0;i>a[i];
sum+=a[i];
if(a[i]>max)
max=a[i];
}
sort(a,a+num,compare); //从大到小排序。
for(len=max;len
下面学习一下
sort函数的用法:
#include
void sort( iterator start, iterator end );
void sort( iterator start, iterator end, StrictWeakOrdering compare );
sort 是对给定区间所有元素进行排序
第一个只需要传递你要排序的串(整形数组等都行)的头指针(数组第一个元素的指针)与数组最后元素的下一个位置。
第二个前面两个参数同第一,但第三个参数是传递一个你定义用于排序的函数。this
举例:
bool compare(int a,int b){
return ab,则为降序
}
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<