UVa307 Sticks (DFS+剪枝)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UVa307 Sticks (DFS+剪枝)相关的知识,希望对你有一定的参考价值。
链接:http://vjudge.net/problem/19648
分析:这题重要的是剪枝。maxd表示的是最小可能长度(把砍完的木棍长度降序排好,最小可能长度大于等于砍完后最长的木棍长度,小于等于总长度的一半,且木棍的根数是整数,所以(总长度%每段最小可能长度=0)),dfs的三个状态分别为cur表示当前要凑maxd长度的木棍已经凑好的长度,from表示从砍完后的第from根木棍开始考虑,cnt表示已经凑好maxd长度木棍的根数。
1.将所有木棍按长度从大到小排序,dfs组合木棍时优先使用长度长的木棍可以加快组合速度,加快找到最优解,并对后续的剪枝起到关键作用。
2.原来木棍的长度大于等于砍完后最长木棍的长度小于等于木棍的总长度。
3.原来木棍的长度一定是总长度的约数,因为木棍的根数一定是整数。
4.当if(cur + a[i] < maxd)时,cur==0时剪枝,因为当当前要凑的木棍集合为空时,加入该空集合的第一根木棍一定是属于该集合的。
5.当else if(cur + a[i] == maxd)并且下一次dfs失败时剪枝,因为优先选择了长度长的木棍组合成maxd长度的木棍,剩下的木棍长度大部分都是砍完后长度小的那些,试想下长度小的木棍组合肯定更灵活,如果剩下的长度小的木棍都没有组合成功,那么放弃当前长度长的木棍转而选择几根长度小的木棍,那么相当于用一根长的木棍和后面几组交换了几根短的木棍,那么后面就更不可能凑成功了。
1 #include <cstdio> 2 #include <cstring> 3 #include <functional> 4 #include <algorithm> 5 using namespace std; 6 7 const int maxn = 105; 8 9 int n, sum, maxd, a[maxn], vis[maxn]; 10 11 bool dfs(int cur, int from, int cnt) { 12 if (cnt * maxd == sum) return true; 13 for (int i = from; i < n; i++) { 14 if (vis[i]) continue; 15 if (cur + a[i] < maxd) { 16 vis[i] = 1; 17 if (dfs(cur + a[i], i + 1, cnt)) return true; 18 vis[i] = 0; 19 if (cur == 0) return false; 20 } else if (cur + a[i] == maxd) { 21 vis[i] = 1; 22 if (dfs(0, 0, cnt + 1)) return true; 23 vis[i] = 0; 24 return false; 25 } 26 } 27 return false; 28 } 29 30 int main() { 31 while (scanf("%d", &n) == 1 && n) { 32 sum = 0; 33 for (int i = 0; i < n; i++) { 34 scanf("%d", &a[i]); 35 sum += a[i]; 36 } 37 sort(a, a + n, greater<int>()); 38 bool ok = false; 39 for (maxd = a[0]; maxd + maxd <= sum; maxd++) { 40 if (sum % maxd == 0) { 41 memset(vis, 0, sizeof(vis)); 42 if (dfs(0, 0, 0)) { 43 ok = true; 44 break; 45 } 46 } 47 } 48 if (!ok) maxd = sum; 49 printf("%d\n", maxd); 50 } 51 return 0; 52 }
以上是关于UVa307 Sticks (DFS+剪枝)的主要内容,如果未能解决你的问题,请参考以下文章