UVA307 Sticks小木棍

题意:一开始有n根同样的小木棍,后来将其切成长度不超过50的小木棍,问原来小木棍最短长度是多少,例如砍完后有四根,长度分别为1,2,3,4,原来长度可能为5,或10。5是最小可能长度。

分析:可以用深搜,因为它的组成长度可能性只是所有木棍长度总和的因数,所以可以直接dfs。

注意剪枝,四个剪枝:

1、当前枚举的长木棍长度不是小木棍长的和的因数时跳过。

2、与当前小木棍长度相同的小木棍没有使用,当前小木棍也不会使用。

3、当前是拼新的长木棍的第一个小木棍,而最后无法拼成的,直接回溯。

4、一根木棍补足长木棍剩余所需长度,而最后无法拼成的,直接回溯。

# include
# include
# include
# include
# include
# include
# include
#include
#include
# include
using namespace std;
const int maxn = 65536;
int a[maxn];
int len;
int maxd;
int vis[maxn];
bool cmp(int u, int v) { return u > v; }
bool dfs(int sum,int cur,int res,int k) {
	if (res==maxd) {
		return true;
	}
	for (int i =cur ; i < len; i++) {
		if (vis[i] || (i&&a[i] == a[i - 1] && !vis[i - 1]))continue;//相同长度的之前没使用,所以这里一样不使用
		if (a[i] + sum == k) {//成功拼成一个小木块
			vis[i] = 1;
			if (dfs(0, 0, res + 1,k))return true;
			vis[i] = 0;
			return false;
		}
		if (a[i] + sum < k) {//没拼好
			vis[i] = 1;
			if (dfs(a[i] + sum, i + 1, res,k))return true;
			vis[i] = 0;
			if (!sum)return false;//最后仍不能拼成
		}
	}
		return false;
}

int main() {
	
	while (cin >> len && len) {
		int sum=0;
		for (int i = 0; i < len; i++) {
			cin >> a[i];
			sum += a[i];
		}
		int ok = 0;
		sort(a, a + len,cmp);
		for (int i = a[0]; i <= sum/2; i++) {//从最大的开始拼
			if (sum % i == 0) {
				memset(vis, 0, sizeof(vis));
				maxd = sum / i;
				if (dfs(0, 0,0,i)) { cout << i << endl; ok = 1; break; }
			}
		}
		if (!ok)cout << sum << endl;
	}
	
	return 0;
}

 

你可能感兴趣的:(紫书第七章)