洛谷P1120 小木棍 (搜索+剪枝)
搜索的经典题。
我们要求木根的最小长度,就要是木根的数量尽可能多,可以发现木根的长度一定可以整除所有小木棒的总长度,从小到大枚举这个可能的长度,第一次有解的就是答案。
关心的状态:当前正在拼哪根木棍,拼到什么长度了,以及每个小木棒的使用情况。
考虑剪枝:
1.优化搜索顺序:小木棒长度从大到小枚举;
2.排除等效冗杂:(1)拼接某根木棍时,小木根长度从大到小枚举,不必每次都将每个都遍历;
(2)如果拼接是一种长度不行,那么相同长度也不行;
(3)长度为0时递归分支返回失败,直接回溯;
(4)长度+a[i]返回失败,直接回溯;
1 #include<bits/stdc++.h> 2 using namespace std; 3 int a[100],v[100],n,len,cnt; 4 bool cmp(int a,int b){ 5 return a>b; 6 } 7 8 bool dfs(int stick,int cab,int last){ 9 if(stick>cnt) return true; 10 if(cab==len) return dfs(stick+1,0,1);//拼下一根木棍 11 int fail=0; 12 for(int i=last;i<=n;i++){ 13 if(!v[i] && cab+a[i]<=len && fail!=a[i]){ 14 v[i]=1;//标记已使用 15 if(dfs(stick,cab+a[i],i+1)) return true; 16 fail=a[i]; 17 v[i]=0;//还原 18 if(cab==0 || cab+a[i]==len) return false;//剪枝 19 } 20 } 21 return false; 22 } 23 24 int main(){ 25 scanf("%d",&n); 26 int sum=0,val=0; 27 for(int i=1;i<=n;i++){ 28 scanf("%d",&a[i]); 29 sum+=a[i];val=max(val,a[i]); 30 } 31 sort(a+1,a+n+1,cmp);//优先搜索较长的木棍 32 for(len=val;len<=sum;len++){ 33 if(sum%len) continue; 34 cnt=sum/len; 35 memset(v,0,sizeof(v)); 36 if(dfs(1,0,1)) break; 37 } 38 cout<<len; 39 }

浙公网安备 33010602011771号