来源
ACwing167-木棒
POJ1011-Sticks
题目简介
本题被称为是剪枝神题之一,因为剪枝角度多达5种,且难以想象。常规的深搜,普通剪枝无法完成此题很有可能会导致超时。
笔者解析
剪枝五种方法列举
- 从大到小排列数组(我们优先使用较长的短木棒,这样可以避免出现类似10=2+3+5,及明明可以用一根却用了三根短木棒的情况)
- 木棒内部编号递增,帮助递归下标管理
- 在爆搜过程中,如果任意大木棒的第一个短木棍在进行了DFS爆搜后,显示这个短木棒不能匹配成指定长度len,但每条短木棍是一定要用的,所以只能说明这个len不满足题意,返回false
- 在爆搜过程中,如果任意大木棒的加了最后一块需要的短木棒在进行了DFS爆搜后,虽然当前小木棒加上后可以匹配一个完整的大木棒,但显示不能匹配,说明在接下来的爆搜过程中有则后面至少有一根大木棍不能用短木棒匹配成len,所以当前len依旧不满足题意,返回false
- 不能匹配后,则跳过所以相等的木棍长度,因为一样的长度同样通不过匹配
笔者代码
java代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
| import java.util.Arrays; import java.util.Scanner;
public class Main { static int n,sum = 0,len; static int[] arr,visit; public static void main(String[] args) { Scanner scanner = new Scanner(System.in); while (true){ n = scanner.nextInt(); if(n == 0){break;} arr = new int[n]; visit = new int[n]; int m; for (int i = 0; i < n; i++) { m = scanner.nextInt(); arr[i] = m; sum+=arr[i]; }
Arrays.sort(arr); int l = 0,r=n-1; while(l<r){ arr[l] = arr[l]+arr[r]; arr[r] = arr[l] - arr[r]; arr[l] = arr[l] - arr[r]; l++; r--; }
for (len = arr[0];len <= sum/2; len++) { if(sum%len == 0&&DFS(0,0,0)==true){ System.out.println(len); break; } }
if(len>sum/2){ System.out.println(sum); } sum = 0; } }
static boolean DFS(int lon,int index,int num){
if(num * len == sum){return true;}
if(lon == len){return DFS(0,0,num+1);}
for (int i = index; i < n; i++) { if(visit[i] == 0&&lon+arr[i]<=len){
visit[i] = 1; if(DFS(lon+arr[i],i+1,num)){return true;} visit[i] = 0;
if(lon == 0){return false;}
if(lon+arr[i] == len){return false;}
int j = i+1; while (j< n && arr[i] == arr[j]){j++;} i = j-1; } } return false; } }
|
c++代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| #include <iostream> #include <cstring> #include <algorithm>
using namespace std;
const int N = 70; int w[N]; int len,n,sum; bool st[N];
bool dfs(int u,int s,int start) { if(u * len == sum) return true; if(s == len) return dfs(u + 1, 0 ,0); for(int i = start; i < n; i ++ ) { if(!st[i] && s + w[i] <= len) { st[i] = true; if(dfs(u, s + w[i], i + 1)) return true; st[i] = false; if(s == 0) return false; if(s + w[i] == len) return false; int j = i + 1; while(j < n && w[i] == w[j]) j++; i = j - 1; } } return false; }
int main() { while(cin>>n) { if(n==0) break; sum = 0; for (int i = 0; i < n; i ++ ) { cin>>w[i]; sum+=w[i]; } sort(w,w+n); reverse(w,w+n); len = w[0]; bool flag = true; while(len<=sum/2) { if(sum % len != 0) { len++; continue; } if(dfs(0,0,0)) { memset(st, false, sizeof st); cout << len <<endl; flag = false; break; } len++; } if(flag) cout << sum <<endl; } return 0; }
|