深度搜索其实就是递归题,找到递归的条件最重要
1.1011 Sticks
解释:George 闲着无聊把一些长度木棒切成了小的棒子,现在他又想把木棒给复原,但是他不知道有几根棒,每根有多长。现在需要你帮助他复原。
解法:
比较经典的深搜题,里面还涉及到了剪枝还有一点小技巧:
1)因为小的棒子比较容易拼接成大的棒子,所以一开始要把大的放在前面。
2)因为是几根长度相同的,所以原先一根棒子的长度是总长度的约数。
3)因为是原先的棒子切成的,所以后来的一根棒子的长度<=原先棒子的长度。
4)如果拼接的长度大于了原先设定的棒子长度,说明这条路失败,可以剪掉。
上代码:
#include<iostream>
#include<algorithm>
#include<memory.h>
using namespace std;
#define MAX 100
int use[MAX],a[MAX],value,n;//n为棒子根数,sum为所有棒子长度和,value为所要求的最短单根棍子长
int sum;//定义全局变量sum
bool cmp(int a,int b){
return a>b;
}//使数组a从大到小排列
bool dfs(int i,int left,int total)//试到了第几根,还要多少能拼接成这根木棒,拼接的总长度。
{
int j;
if(left==0)
{
total-=value;//寻找新棒子
if(total==value)
return 1;//如果只剩下value长度的没拼接,那么一定是能拼成这个长度的,这是剪枝1。
if(total<value)
return 0;//如果剩下的长度小于原先木棒的长度,那么一定拼不成了,可以返回失败了,这是剪枝2。
for(i=0;i<n;i++)
if(!use[i])
break;
use[i]=1;//找到第一根没有用过的小木棒,置为用过,去做深搜。
if(dfs(i+1,value-a[i],total))
return 1;//成功的话,返回1
use[i]=0;//不成功的话,重新置为0
total+=value;//这个value可能不是合适的木棒长度。
return 0;
}
else{
for(j=i;j<n;j++)
{
if(a[j]>left||use[j])
continue;//如果用过或者大于剩余长度,略过,此为剪枝3.
if((a[j]==a[j-1])&&!use[j-1])
continue;//如果前一根和后一根相等,且前一根没有用,那么表示这个长度之前就失败了,这次可以不要去深搜了,此为剪枝4.
use[j]=1;
if(dfs(j+1,left-a[j],total))
return 1;
use[j]=0;
}
return 0;
}
return 0;
}
int searchfactor(int a[],int n){
int k=0;//k是判断是否找到了小于sum的因子
for(value=a[0];value<=sum/2;value++)
{
if(sum%value!=0)//若时间超了,去掉=
continue;
k=dfs(0,value,sum);
if(k!=0)
return value;
}
if(k==0)
return sum;//若循环后没有则输出sum
}
int main()
{
int i;
while((scanf("%d",&n)!=EOF)&&n)
{
memset(use,0,sizeof(use));
sum=0;
for(i=0;i<n;i++)
{
scanf("%d",&a[i]);
sum+=a[i];
}
sort(a,a+n,cmp);
printf("%d\n",searchfactor(a,n));
}
return 0;
}