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

 

posted @ 2023-07-24 16:08  浪矢-CL  阅读(53)  评论(0编辑  收藏  举报