洛谷 P1120 小木棍
排序后枚举原来木棍的长度,然后去搜索,搜索成功则结束程序。
搜索不成功的则尽早退出搜索。
剪枝:
顺序剪枝:对木棍排序,然后先用大的后用小的
(若a=b+c,则如果既可以使用a也可以使用b+c那么使用a,因为b和c可能会在后面单独被用到
而且,先用大的去拼可以更快的排除错误选项)
等效性剪枝:当前状态下,长度为a[i]的用过不行,那就换一个长度不要用等长度的a[i+1]去尝试了
可行性剪枝 :如果使用当前木棍正好拼成H但上面没有return 则该H不行
h==0是对第一次搜索一定要能第一根木棍 才合法
#include<iostream>
#include<queue>
#include<cstdio>
#include<algorithm>
#include<math.h>
#include<string.h>
using namespace std;
int n,a[69],cnt,c,m;
int ans=0,vis[70];
int tot,maxn;
bool cmp(const int x,const int y) { return x>y;}
//当前高度 上一个木棍编号 还需拼几根木棍 目标长度
void dfs(int h,int last,int sum,int H)
{
if(sum==0)
{
printf("%d",ans);
exit(0);
}
for(int i=last+1;i<=n;i++)
if(!vis[i])
{
if(h+a[i] < H)
{
vis[i]=1;
dfs(h+a[i],i,sum,H);
vis[i]=0;
}
if(h+a[i] == H)
{
vis[i]=1;
dfs(0,0,sum-1,H);
vis[i]=0;
}
if(h+a[i]==H || h==0) break;
// /可行性剪枝 如果使用当前木棍正好拼成H但上面没有return 则该H不行
//可行性剪枝 h==0是对第一次搜索一定要能第一根木棍 才合法
while( a[i+1] == a[i]) i++;
//排除等效剪枝,长度为a[i]的用过了就不要再去用了
}
return ;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&c);
a[i]=c;
tot+=c;
maxn=max(maxn,c);
}
sort(a+1,a+1+n,cmp);//顺序剪枝
int sum=0;
for(int i=maxn;i<=tot;i++)//i每根长度,tot/i,根数
{
if(tot%i) continue;
sum=tot/i;ans=i;
dfs(0,0,sum,i);
}
return 0;
}