POJ1011

参考博文:https://www.cnblogs.com/zqy123/p/4921564.html

问题分析:

原棍子长度范围在锯断后最长的棍子长度到所有棍子的总长度之内,所以从小到大循环遍历可能的原棍子长度,符合条件的长度即结果。

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int Max = 65;
int sticks[Max]; //存储每根棍子的长度 
int note[Max]; //记录当前下标的棍子是否用过 
int sticks_len; //要合成的棍子的长度 
int sticks_num; // 长度为sticks_len下一共有多少根棍子 
int sticks_sum; //所有棍子的总长度 
int num;

int dfs(int n, int k, int cnt) { //n为正在合并的棍子的长度,k为当前要处理的木棍的下标,cnt为已经合成好的棍子的数量 
	if (cnt == num) return 1;
	if (n == sticks_len)  //已经合并好一根棍子,继续合下一根 
		return dfs(0,0,cnt+1);
	int i,pre = 0; //i是木棍的下标,pre保存重复木棍 
	for (i = k; i < sticks_num; i++) {
		if (note[i] == 0 && n+sticks[i] <= sticks_len && sticks[i] != pre) { //如果当前选择棍子的长度是pre,则下一根选择的棍子的长度要小于pre,降低运行时间 
			pre = sticks[i];  
			note[i] = 1;
			if (dfs(n+sticks[i], i+1, cnt)) 
				break;
			note[i] = 0;
			if (k == 0)//如果第一根棍子(最长的那根)不能参与合成,那么其余的棍子也无法合成 
				return 0;
		}
	}
	if (i == sticks_num) 
		return 0;
	else 
		return 1;
}

int main() {
	while (cin >> sticks_num, sticks_num != 0) {
		sticks_sum = 0;
		for (int i = 0; i < sticks_num; i++) {
			cin >> sticks[i];
			sticks_sum += sticks[i];
		}
		sort(sticks, sticks+sticks_num, greater<int>());
		for (sticks_len = sticks[0]; sticks_len <= sticks_sum/2; sticks_len++) { //循环遍历,原棍子长度等于总长度或小于等于总长度的两倍 
			if (sticks_sum%sticks_len == 0) { //总长度肯定是原棍子长度的倍数 
				num = sticks_sum/sticks_len; 
				memset(note, 0, sizeof(int)*sticks_num); //初始化记录数组,所有棍子都没用过 
				if (dfs(0,0,0)) break;
			}
		}
		if (sticks_len > sticks_sum/2) 
			cout << sticks_sum << endl;
		else 
			cout << sticks_len << endl;
	}
	return 0;
}

 

posted @ 2018-12-06 19:34  JonnyOu1012  阅读(31)  评论(0编辑  收藏  举报