POJ 1011 - Sticks DFS+剪枝

POJ 1011 - Sticks
题意:
    一把等长的木段被随机砍成 n 条小木条
    已知他们各自的长度,问原来这些木段可能的最小长度是多少

分析:
    1. 该长度必能被总长整除
    2. 从大到小枚举,因为小长度更灵活, 可拼接可不拼接
    3. 因为每一跟木条都要用到, 故若轮到其中一根原始木段选它的第一根木条时,若第一根木条若不满足,则显然第一根木条在接下来任何一根原始木段都不会满足,故无解
    4. 由于所有棒子已排序,在DFS时,若某根棒子未被选,则跳过其后面所有与它等长的棒子

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 using namespace std;
 6 int n, sum, ans, len, Max;
 7 int a[100],vis[100];
 8 bool dfs(int num,int x,int j)
 9 {
10     if(x == 0)
11     {
12         num--;
13         if(num == 0) return 1;
14         int i = n;
15         while(vis[i]) i--;
16         vis[i] = 1;
17         if(dfs(num, len - a[i], i-1) ) return 1;
18         vis[i] = 0;
19     }
20     else
21     {
22         for (int i = j; i > 0; i--)
23         {
24             if (vis[i]) continue;
25             if (!vis[i+1] && a[i+1] == a[i]) continue;
26             if (x < a[i]) continue;
27             vis[i] = 1;
28             if(dfs(num, x - a[i], i-1)) return 1;
29             vis[i] = 0;
30         }
31     } 
32     return 0;
33 }
34 int main()
35 {
36     while(~scanf("%d",&n) && n)
37     {
38         sum = 0, Max = 0;
39         for (int i = 1; i <= n; i++){
40             scanf("%d", &a[i]);
41             sum += a[i];
42             Max = max(a[i], Max);
43         } 
44         sort(a+1,a+1+n);
45         ans = sum;
46         for (int i = Max; i < sum ; i++)
47         {
48             if (sum % i) continue;
49             len = i;
50             memset(vis,0,sizeof(vis));
51             if(dfs(sum/i, len, n)) 
52             {
53                 ans = i;
54                 break;
55             }
56         }
57         printf("%d\n", ans);
58     }
59 }

 

posted @ 2016-08-13 21:38  nicetomeetu  阅读(163)  评论(0编辑  收藏  举报