POJ 1011
//代码比较长,好在逻辑比较清晰吧 //调bug调了挺久,错在 我直接返回false,未回撤对visit的修改。因为在当前情况下不可行,不代表其他深搜路劲不行 #include <cstdio> #include <algorithm> #include <cstring> using std::sort; using std::memset; int n; const int MAX = 70; int stick[MAX]; bool visit[MAX]; bool cmp(int a,int b) { return a>b; } bool match(int singlelength, int remain, int startindex, int matchnum) { if(matchnum == n) return true; if(remain == singlelength)//剪枝2:重拼一个木棍的时候,只需要看第一个要匹配的能不能成功 { while(visit[startindex] && startindex< n) startindex++; if(remain == stick[startindex]) { visit[startindex] = true; if( match(singlelength, singlelength, 0, matchnum+1)) return true; visit[startindex] = false; } else { visit[startindex] = true; if(match(singlelength, remain-stick[startindex], startindex, matchnum+1)) return true; visit[startindex] = false; } } else { int same1 = -1;//剪枝3:相同的木棍,如果不行,不需要重试。 for(int i = startindex ; i < n; i++) { if(visit[i] || same1 == stick[i]) continue; if(remain < stick[i]) continue; if(remain == stick[i]) { visit[i] = true; if(match(singlelength, singlelength, 0, matchnum +1)) return true; else same1 = stick[i]; visit[i] = false; } else{ visit[i] = true; if(match(singlelength, remain-stick[i], i, matchnum+1)) return true; else same1 = stick[i]; visit[i] = false; } } } return false; } int main() { while(scanf("%d",&n)&&n) { int maxlength = 0; int sumlength = 0; memset(visit, 0, sizeof(visit)); for(int i= 0 ; i < n; i++) { scanf("%d",&stick[i]); if(maxlength < stick[i]) maxlength = stick[i]; sumlength += stick[i]; } sort(stick, stick+n, cmp); bool flag = false; //剪枝1:只有sumlength的约数才有可能成为dividelength,这里dividelength表示拼成的木棍长 for(int dividelength = maxlength; dividelength <= sumlength; dividelength ++) { if(sumlength % dividelength) continue; memset(visit, 0, sizeof(visit)); if(match(dividelength, dividelength, 0, 0)) { printf("%d\n",dividelength); flag = true; break; } } } return 0; }