传送门
http://poj.org/problem?id=1011
题目大意
已知原来有等长若干木棒,现在给你一堆断了的木棒的长度,问原来的木棒最短是多长
题目类型
DFS + 剪枝 + “贪心优化”
思路
http://blog.csdn.net/lyy289065406/article/details/6647960
三个剪枝
1)设最长的木棒长度max ,木棒长度和sum, 则可能区间为[max, sum/2] 并且 长度能被sum整除
2)一次拼接中,一次循环中,同长度的木棒只检测一次
3)每次拼接的第一个木棒,如果不成功则说明这个木棒一定不能成功。所以break
一个优化
需要逆序搜索。(两个短的比一个长的更有用。)
代码
#include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> using namespace std; #define N 70 //int visnum; int mu[N]; bool vis[N]; int n; int ncount = 0; bool dfs(int goal,int visnum, int len=0, int s = n-1) { ncount++; //int succeed = 0; if (visnum == n) { return true; } int last = -1; for (int i = s; i >= 0; i--) { if (vis[i] ||mu[i] == last) continue; //if (!vis[i] && mu[i] != last && mu[i] + len <= goal) { //last = mu[i]; vis[i] = true; //visnum++; if (mu[i] + len < goal) { if (dfs(goal,visnum+1, len+mu[i],i)) return true; else last = mu[i]; } else if (len + mu[i] == goal) { if (dfs(goal,visnum+1)) return true; else last = mu[i]; } vis[i] = false; //visnum--; if (len == 0) break; //} } return false; } int main() { while (scanf("%d", &n)+1 && n) { int i; int sum = 0; int max = 0; for (i = 0; i < n; i++) { scanf("%d", &mu[i]); sum += mu[i]; if (mu[i] > max) max = mu[i]; } sort(mu, mu+n); //visnum = 0; //memset(vis,0,sizeof(vis)); //printf("454 = %d ",dfs(454)); for (i = max; i <= sum/2; i++) { if (sum % i == 0) { //printf("search %d ", i); //visnum = 0; memset(vis, false, sizeof(vis)); if (dfs(i,0) == 1) break; //printf("search end "); } } //printf("sum = %d ", sum); if (i >= sum/2+1) i = sum; printf("%d ", i); //printf("count = %d ", ncount); } return 0; }