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;
}
}
}
}
}