洛谷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 }

 

posted @ 2022-04-29 16:01  YHXo  阅读(86)  评论(0)    收藏  举报