题意 : 有n根木棍(n<=64),它们由一些相同长度的木棍切割而来,给定这n根木棍的长度,求使得原来长度可能的最小值。
分析 : 很经典的深搜题目,我们发现答案只可能是所有木棍长度总和的因数,那么我们只要去枚举因数然后搜索是否可行即可!具体实现看代码可能更容易看懂,这里不赘述。重要的是体会此类深搜的代码构建过程以及剪枝的考虑的巧妙性!
#include<stdio.h> #include<algorithm> #include<string.h> using namespace std; const int maxn = 64 + 5; bool vis[maxn]; int sticks[maxn]; int CurLen; int n; int Remain;///每一次都去重置为 bool DFS(int id, int Lack)///传入的参数为上次选择了哪个木棍、当前还缺多少才能组成一个新的目标木棍 { if(Lack == 0){///已经组成一个新的木棍了, Remain -= CurLen; if(Remain == 0) return true;///如果当前总长为0,说明此方案可行! int which; for(which=0; vis[which]==true; which++);///由于是排好序,我们取第一个没有使用过的木棍开始下一次的搜索 vis[which] = true;///标记 if( DFS(which, CurLen-sticks[which]) ) return true;///开始新一轮搜索 vis[which] = false;///记得标记回来 Remain += CurLen;///赋值回来!搜索题代码应当注意的地方! }else{ for(int i=id; i<n; i++){ if(i>0 && (sticks[i]==sticks[i-1] && !vis[i-1])) continue;///剪枝:排序后,如果有数字不能返回true,说明在此刻选 ///择同样的数字也是一样的结果,所以跳过 if(vis[i] || Lack < sticks[i]) continue; Lack -= sticks[i]; vis[i] = true; if( DFS(i, Lack) ) return true; Lack += sticks[i]; vis[i] = false; if(sticks[i] == Lack) break;///剪枝:如果当前if成立,说明刚刚的DFS肯定是 ///到达过Lack==0的,既然不返回true,那么说明 ///此方案不行,不必继续往下面搜下去了! } } return false; } bool cmp(int fir, int sec){ return fir > sec; } int main(void) { while(~scanf("%d", &n) && n){ int tot = 0; for(int i=0; i<n; i++){ scanf("%d", &sticks[i]); tot += sticks[i];///累计总和 vis[i] = false; } sort(sticks, sticks+n, cmp);///排序方便剪枝 bool ok = false; for(int Len=sticks[0]; Len<=tot/2; Len++){ if(tot % Len == 0){ Remain = tot;///将Remain重置,代表当前搜索状态下总长度还剩多少,如果为0说明成功 CurLen = Len;///全局变量记录当前枚举的是哪个因数,方便深搜操作 if(DFS(0, Len)){ printf("%d\n", Len); ok = true; break; } } } if(!ok) printf("%d\n", tot); } return 0; }
时间: 2024-10-01 06:14:36