[题解]小木棍sticks--洛谷1120

原题链

提交情况:AC

主要算法:

这是一道广搜经典题,主要考察剪枝。现将每一根切断后的木棍输入并按照从大到小排序(剪枝1);

接着从木棍中的最大值开始枚举(剪枝2),一直枚举到所有木棍的总长,因为这些木棍是要拼接的,只有在最大长度之后的结果才有可能。

接着,我们考虑这么分是否合理:如果总长除以枚举的原来没有切的长度不能整除,很明显是行不通的(剪枝3)。

之后开始深搜,如果当前拼接的木棍所用的木棍根数比我们事先枚举的要多,证明这是行的通的(因为这证明前cnt个都可以成功拼接)

Ps:(cnt为事先枚举每根拼接木棍所用的木棍根数)(剪枝4)。如果当前拼接木棍的长度等于事先枚举的长度就表明这一根木棍拼接成功,进入拼接下一根木棍。其他的剪枝和代码在程序中都有注释解释,比较看、好懂。

源代码

#include <bits/stdc++.h>
using namespace std;
int len,cnt,n,a[1010];
bool vis[1010];
inline bool dfs(int stick,int cab,int last){
/*
	last:代表当前从那根木棍继续拼接
	cab:代表当前正在拼的木棍的长度
	stick:代表已经拼接好的木棍由几根木棍组成 
*/
	if(stick > cnt)return true;//上一次递归已经成功拼接了cnt跟木棍,这次直接return 
	if(cab == len)return dfs(stick + 1,0,1);//当前拼接的木棍满足要求,继续拼接下一个木棍 
	int fail = -1;
	for(int i = last;i <= n;i++){
		if(!vis[i] && cab + a[i] <= len && fail != a[i]){
			vis[i] = true;
			if(dfs(stick,cab + a[i],i + 1))return true;
			vis[i] = false;fail = a[i];
			if(cab == 0 || cab + a[i] == len)return false;
		}
	}
	return false;
}
inline bool cmp(int x,int y){
	return x > y; 
}
int main(){
	while(cin>>n){
		if(n == 0)return 0;
		memset(vis,false,sizeof(vis));
		int maxx = -1,sum = 0;
		for(int i = 1;i <= n;i++){
			cin>>a[i];
			if(a[i] > 50){i--;n--;continue;}
			sum += a[i];
			maxx = max(maxx,a[i]);
		}
		sort(a + 1,a + n + 1,cmp);
		for(len = maxx;len <= sum;len++){//len:枚举切割之前每根完整木棍的长度 
			if(sum % len)continue;
			cnt = sum / len;//cnt代表当前枚举的木棍长度应该由cnt根木棍组成 
			if(dfs(1,0,1))break;
		}
		cout<<len<<endl;
	}
	return 0;
} 
posted @ 2019-10-26 08:13  czyczy  阅读(503)  评论(0编辑  收藏  举报