poj dfs相关之1011 Sticks
这道题是比较经典的回溯题,而且剪枝很重要,不然会超时:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 70;
int n, ans, len,num;
int stick[maxn];
bool mark[maxn];
bool cmp(int i, int j)
{
return i > j;
}
bool dfs(int sum, int dep, int i)
{
if (dep == num - 1)//剪枝1:与dep==num等价,剩下的构成最后一个小棒
{
ans = 1;
return true;
}
if (ans)
return true;
int t, tmp;
for (t = i; t < n; t++)
{
if (mark[t] == 1)
continue;
mark[t] = 1;
if (sum + stick[t] < len)
{
if (dfs(sum + stick[t], dep, i + 1))
return true;
}
else if (sum + stick[t] == len)
{
if (dfs(0, dep + 1, 0))
return true;
}
mark[t] = 0;
if (sum == 0)//剪枝2:如果第一个小棒就找不到组合的话(此时所有递归都退出到这儿,和为0),则break。这里如果不剪枝的话一定会超时
break;
while (stick[t] == stick[t + 1] && t < n)t++;//剪枝3,stick[t]不行的话,与他相同的也不行(前提是降序排列)
}
return false;
}
int main()
{
freopen("1.txt", "r", stdin);
int i, j, k, sum;
while (scanf("%d", &n) != EOF&&n != 0)
{
k = 0;
sum = 0;
for (i = 0; i < n; i++)
{
scanf("%d", &stick[i]);
k = max(k, stick[i]);
sum += stick[i];
}
sort(stick, stick + n, cmp);
for (len = k; len <= sum; len++)//剪枝4:循环从K开始
{
if (sum%len == 0)
{
memset(mark, 0, sizeof(mark));
ans = 0;
num = sum / len;
dfs(0, 0, 0);
if (ans)
{
printf("%d\n", len);
break;
}
}
}
}
}