POJ1011 Sticks

题目来源:http://poj.org/problem?id=1011

题目大意:George有一些等长的木棍,他把这些木棍随机地砍断,砍断后的木棍最多50单位长。现在他想把木棍拼回原来的长度,但他已经忘记了原来有多少根木棍和原来的木棍有多长。请帮他设计一个程序计算原始木棍的最小长度。所有木棍的长度都是正整数单位长度。

输入:含多个数据块,每个数据块为一个测试用例,第一行为一个整数,表示砍断后有多少根木棍,最大为64.第二行为每根木棍的长度,以空格分开。输入的最后一行为0。

输出:每个测试用例对应一行,含一个整数:最小的可能原始木棍长度。


Sample Input

9
5 2 1 5 2 1 5 2 1
4
1 2 3 4
0

Sample Output

6
5

对问题进行分析发现,我们可以把可能解确定在一个范围内:

  1.原始长度最小为砍断后最长的那根木棍的长度

  2.因为木棍的总长度不变,那么原来木棍最长为现有所有短木棍拼起来的长度

  3.因为木棍都为整数单位长度,且对木棍进行砍断后,木棍数目只会增加而不可能减少,所以若总长度不能整除一个候选解或某候选解对应的原始木棍根数多于现在木棍的根数,显然都不可能成为可行解

  基于以上的思想,用DFS+剪枝实现。

 1 //////////////////////////////////////////////////////////////////////////
 2 //        POJ1011 Sticks
 3 //        Memory: 284K        Time: 16MS
 4 //        Language: C++        Result: Accepted
 5 //////////////////////////////////////////////////////////////////////////
 6 
 7 #include <iostream>
 8 #include <stdlib.h>
 9 using namespace std;
10 
11 bool buff[64];
12 int stick[70];
13 bool visit[70];
14 int n;
15 
16 int campare(const void * a, const void * b) {
17     return *((int *)b) - *((int *)a);
18 }
19 
20 bool dfs(int * stick, bool * visit, int len, int initLength, int start, int num) {
21     if (num == n) {
22         return true;
23     }
24     int sample = -1;
25     for (int i = start; i < n; i++) {
26         if (visit[i] == true || stick[i] == sample) {
27             continue;
28         }
29         visit[i] = true;
30         if (len + stick[i] == initLength) {
31             if (dfs(stick, visit, 0, initLength, 0, num + 1)) {
32                 return true;
33             } else {
34                 sample = stick[i];
35             }
36         } else if (len + stick[i] < initLength) {
37             if (dfs(stick, visit, len + stick[i], initLength, i, num + 1)) {
38                 return true;
39             } else {
40                 sample = stick[i];
41             }
42         }
43         visit[i] = false;
44         if (len == 0) 
45             break;
46     }
47     return false;
48 }
49 
50 int main(void) {
51     while (true) {
52         int totalLength = 0;
53         cin >> n;
54         if (n == 0) {
55             break;
56         }
57         for (int i = 0; i < n; i++) {
58             cin >> stick[i];
59             visit[i] = false;
60             totalLength += stick[i];
61         }
62         qsort(stick, n, sizeof(int), campare);
63         int maxLength = stick[0];
64         bool findSolution = false;
65         //检验每个可能的可行解
66         for (int initLength = maxLength; initLength <= totalLength - initLength; initLength++) {
67             //isSolution标记是否找到可行解
68             int oriCount = 0;
69             //totalLength能被i整除,oriCount表示原始木棍数
70             if (totalLength % initLength != 0) {
71                 continue;
72             }
73             if(dfs(stick, visit, 0, initLength, 0, 0) == true) {
74                 cout << initLength << endl;
75                 findSolution = true;
76                 break;
77             }
78         }
79         if (!findSolution) {
80             cout << totalLength << endl;
81         }
82     }
83     system("pause");
84     return 0;
85 }
View Code
posted @ 2013-07-30 23:34  小菜刷题史  阅读(254)  评论(0编辑  收藏  举报