题意:有一堆的木棒,长度不一,它们是有一些整齐的木棒截断而成的,求最小的木棒原始长度。
思路很简单深搜,但是直接深搜的话会tle,首先可以对木棒长度进行排序从大到小,优先使用长度长的木棒,加入当前长度不符合,考虑下一个木棒
其次如果长度为零的时候选择木棒失败,那么直接退出,实测加上这一剪枝就可以ac,这一剪枝可以帮助我们尽可能的在靠近树根处剪枝,所以优化效果很明显。
然后是如果这次选择的木棒长度和上次失败时的一样,那么剪枝。
#include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<iostream> #include<algorithm> #include<vector> #include<map> #include<queue> #include<stack> #include<string> #include<map> #include<set> #define eps 1e-6 #define LL long long using namespace std; const int maxn = 70; const int INF = 0x3f3f3f3f; int n, sumv, target, aim;//target表示目标的棍子个数,aim表示目标的棍子长度 int stick[maxn], vis[maxn]; bool cmp(int a, int b) { return a > b; } void init() { sumv = 0; for(int i = 0; i < n; i++) { cin >> stick[i]; sumv += stick[i]; } sort(stick, stick+n, cmp); } bool dfs(int cnt, int len, int pos) { if(cnt == target) return true; if(len == aim) return dfs(cnt+1, 0, 0); for(int i = pos; i < n; i++) { //从大到小排序后,按顺序搜索 if(!vis[i] && len+stick[i] <= aim) { vis[i] = 1; if(dfs(cnt, len+stick[i], i+1)) return true; vis[i] = 0; if(len == 0) return false; //如果第一根时失败剪枝 while(i+1 < n && stick[i+1] == stick[i]) i++; //如果下一根长度跟当前的失败的长度一样,剪枝 } } return false; } void solve() { int ans = 0; for(int i = 1; i <= sumv; i++) if(sumv % i == 0) { memset(vis, 0, sizeof(vis)); aim = i; target = sumv / aim; if(dfs(0, 0, 0)) { ans = aim; break; } } cout << ans << endl; } int main() { // freopen("input.txt", "r", stdin); while(scanf("%d", &n) == 1 && n) { init(); solve(); } return 0; }
时间: 2024-10-09 19:11:57