题意:给n(n<=64)根小木棒,每根木棒长度最大为50,问最小能把他们拼成长度为多少的木棒使得小木棒不剩余。
题解:经典dfs+剪枝。总结起来三个剪枝,具体见代码。
Sure原创,转载请注明出处
#include <iostream> #include <cstdio> #include <memory.h> #include <algorithm> using namespace std; const int maxn = 70; int stick[maxn]; bool vis[maxn]; int sum,n,cur; bool cmp(const int &a,const int &b) { return a > b; } void read() { sum = 0; for(int i=0;i<n;i++) { scanf("%d",&stick[i]); sum += stick[i]; } sort(stick , stick + n , cmp); return; } bool dfs(int st,int cnt,int len) { if(len == cur) //剪枝1 : 对于当前长度为cur的第一根木棒一定是剩余最大的 { for(int i=0;i<n;i++) { if(vis[i] == false) { vis[i] = true; if(dfs(i+1,cnt,len-stick[i]) == false) { vis[i] = false; return false; } return true; } } return false; } if(len == 0) { if(cnt == 1) return true; else return dfs(0,cnt-1,cur); } for(int i=st;i<n;i++) { if(vis[i]) continue; if(i > 0 && vis[i-1] == false && stick[i] == stick[i-1]) continue; //剪枝2 : 如果i小木棒和i-1小木棒长度相等且i-1未使用,则跳过i if(len >= stick[i]) { vis[i] = true; if(dfs(i+1 , cnt , len - stick[i])) return true; vis[i] = false; if(len == stick[i]) return false; //剪枝3 : 如果当前最后一根木棒恰好为剩余长度都不能满足,那么直接返回上一层 } } return false; } void solve() { int res = -1; for(int i=stick[0];i<sum;i++) { if(sum % i == 0) { memset(vis,false,sizeof(vis)); cur = i; if(dfs(0,sum/i,i)) { res = i; break; } } } if(res == -1) res = sum; printf("%d\n",res); return; } int main() { while(scanf("%d",&n) && n) { read(); solve(); } return 0; }