/*
思路:
首先说说暴力搜索的思路,先将数组排序,然后从第一个开始遍历,找和为target的组合
找到一组后,再从头开始找另一组,直到全部匹配为止
剪枝策略:
1. target肯定介于最大值和sum之间
2. target肯定能被sum整除
3. 排序后可能有相邻两个数相等的情况,如果前一个不符合条件,那么当前的就不用再执行递归了
*/
#include <iostream>
#include <algorithm>
using namespace std;
const int MAX_NUM = 128;
int stick[MAX_NUM];
bool used[MAX_NUM];
//origin_num为木棒数,等于sum/target
int n, origin_num, target;
bool dfs(int start, int left, int success)
{
if (left == 0){
if (success == origin_num){ //如果匹配的木棒数等于原始木棒数
return true;
}
else{ //否则继续匹配,找下一组
for (start = 0; used[start]; ++start);//找第一个没有用过的木棒
used[start] = true;
if (dfs(start+1, target-stick[start], success+1)){
return true;
}
else{
used[start] = false;
return false;
}
}
}
else{
for (int i = start; i < n; ++i){
if (used[i] || left < stick[i]){ //如果已经用过或者长度大于left
continue;
}
if((stick[i] == stick[i-1]) && !used[i-1]) //剪枝策略3
continue;
used[i] = true;
if (dfs(i+1, left-stick[i], success)){
return true;
}
used[i] = false;
}
return false;
}
}
bool compare(int a, int b)
{
return a > b;
}
int main()
{
while (scanf("%d", &n) && n != 0){
memset(used, 0, sizeof(used));
int sum = 0;
for (int i = 0; i < n; ++i){
scanf("%d", &stick[i]);
sum += stick[i];
}
sort(stick, stick+n, compare);
for (target = stick[0]; target <= sum; ++target){ //剪枝策略1
if (sum % target == 0){ //剪枝策略2
origin_num = sum / target;
if (dfs(0, 0, 0)){
printf("%d\n", target);
break;
}
}
}
}
}
POJ 1011 (DFS+剪枝)
最新推荐文章于 2020-03-05 11:15:01 发布