【Luogu P1120】小木棍

题目:

乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过$50$。
现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度。
给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度。

分析:

可以很轻易的写出$\rm dfs$的程序:

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 const int MAXN = 105;
 6 
 7 int st[MAXN], n, s = 0;
 8 bool vis[MAXN];
 9 
10 void dfs(int cur, int len, int w) {
11     if(cur == s / len) {
12         cout << len << endl;
13         exit(0);
14     }
15     if(w == 0) {
16         dfs(cur + 1, len, len);
17         return;
18     }
19     for(int i = n - 1; i >= 0; i--)
20         if(w - st[i] >= 0 && !vis[i]) {
21             vis[i] = true;
22             dfs(cur, len, w - st[i]);
23             vis[i] = false;
24         }
25 }
26 
27 int main() {
28     cin >> n;
29     for(int i = 0; i < n; i++) {
30         cin >> st[i];
31         s += st[i];
32     }
33     sort(st, st + n);
34     for(int i = 1; i <= s; i++)
35         if(s % i == 0) {
36             dfs(0, i, i);
37         }
38     return 0;
39 }
View Code

然而,上面的代码时间复杂度是$O(n! \log  \sum a_i)$左右,显然不可以接受。

首先我们发现:

$1$)从按木棍大到小搜索,因为长度小的比长度大的更加灵活。

$2$)若当前剩余长度$\lt$最小的木棍的长度,那么这个方案就没用了

$3$)如果当前长度的木棍拼接无法成功,那么同样长度的木棍拼接也无法成功。

$4$)若选择这个木棍来拼接后没有成功,且当前的剩余长度$=$这个木棍的长度,应当直接退出,因为这根木棍显然要自成一个大木棍,而拼下去却失败,说明剩下的小木棍无法拼接成这根木棍。

$5$)若选择这个木棍来拼接后没有成功,且当前的剩余长度$=$我们枚举的长度$len$,应当直接退出,因为这根木棍肯定会需要用上,而这里失败了,说明它最后用不到了。

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 const int MAXN = 105, inf = 1e9;
 6 
 7 int st[MAXN], n, s = 0, len, maxi = -inf, mini = inf;
 8 bool vis[MAXN];
 9 
10 void dfs(int cur, int w, int last) {
11     if(cur == s / len) {
12         cout << len << endl;
13         exit(0);
14     }
15     if(w == 0) {
16         dfs(cur + 1, len, -1);
17         return;
18     }
19     if(w < mini) return;
20     for(register int i = last + 1; i < n; i++)
21         if(w - st[i] >= 0 && !vis[i]) {
22             vis[i] = true;
23             dfs(cur, w - st[i], i);
24             vis[i] = false;
25             while(i && st[i] == st[i - 1]) i++;
26             if(w == st[i] || w == len) return;
27         }
28 }
29 
30 int main() {
31     cin >> n;
32     for(register int i = 0; i < n; i++) {
33         cin >> st[i];
34         s += st[i];
35         maxi = max(maxi, st[i]);
36         mini = min(mini, st[i]);
37     }
38     sort(st, st + n, [](int x, int y){
39         return x > y;
40     });
41     for(register int i = maxi; i <= s; i++)
42         if(s % i == 0) {
43             len = i;
44             dfs(0, i, -1);
45         }
46     return 0;
47 }
View Code

 

posted @ 2018-08-23 10:23  zhylj  阅读(159)  评论(0)    收藏  举报