【XDU ACM周训】 Week 4 - L Sticks(DFS+剪枝)

题目大意:

给不超过64根棍子,将它们分成长度相等的若干组,使每组长度最小

分析:

此题是K题Square的升级版:https://blog.csdn.net/wangyucong1999310/article/details/80541217

棒子多了,组数还需要枚举。做法大体相同,需要多两个剪枝的地方:

1.棒子是从大到小排序的,所以如果某一组的第一根棒子搜索失败,就没必要再搜了。因为每根棒子都要用上,第一根棒子搜索失败,那么它在后面也一定用不上。

2.如果某一组的最后一根棒子搜索失败,也没必要再搜了。为什么呢?假设搜索失败的这根长度为m,就算后面可以有若干个小棒组合成m顶替它的位置也不行。因为若干个小棒用起来可以自由组合,即使这样都搜索失败,把它们拼成m来用自然更不可能成功


代码:

#include <iostream>
#include <algorithm>
#include <string.h>
using namespace std;

int n, num[64] = {0};
bool found, vis[64] = {0};

void dfs(int len, int now, int c, int start){
	if (now == 0){//找到一组,重设参数
		now = len;
		c--;
		start = 0;
	}
	if (c == 1) found = 1;//找到n-1组,跳出
	if (found) return;
	for (int i = start, last = -1; i < n; i++){//从上一根棒子的位置开始找
		if (vis[i] || num[i] > now || num[i] == last) continue;
		vis[i] = 1;
		dfs(len, now-num[i], c, i+1);
		if (found) return;
		vis[i] = 0;
		last = num[i];
		if (now == len || now == num[i]) return;//剪枝,第一根或最后一根失败时直接返回 
	}
}

bool cmp(int a, int b){
	return (a > b);
}

int main(){
	while (cin >> n){
		if (n == 0) return 0;
		int sum = 0;
		for (int i = 0; i < n; i++){
			cin >> num[i];
			sum += num[i];
		}
		sort(num, num + n, cmp);
		for (int i = n; i > 1; i--){//枚举组数 
			if (sum % i == 0){
				found = 0;
				memset(vis, 0, sizeof(vis));
				dfs(sum/i, sum/i, i, 0);
				if (found){
					cout << sum / i << endl;
					goto exit;
				}
			}
		}
		cout << sum << endl;
		exit:;
	}
}

猜你喜欢

转载自blog.csdn.net/wangyucong1999310/article/details/80541294
今日推荐