TOJ 1009. Sticks 【搜索+剪枝】

        很难的搜索,对剪枝要求很高,不过在做这个题之前做过一个类似的,所以直接用以前那个DFS就过了。

        大意是给定N个木棍长度,(不大于50)要求找出最小的长度L使得可以将这些木棍拼成若干长度L的木棍。

        就是搜索,不过对剪枝要求很高,不然很容易TLE,黑书上有提到过这道题。变态的是TOJ有数据是木棍大于50,所以必须忽略掉这些不合理的数据。

        以前那个很像的题是说给一堆木棍长度,问能否将这些木棍拼成一个正方形,其实和这个题差不多,只不过这个题枚举一下棍子长度和的约数就好了。

#include #include #include using namespace std; int a[105]; bool mark[105],flag; int n,sum,cont,ave,number; //number of sticks,sum of len,num is number of original sticks bool cmp(const int &a,const int &b){ return a>b; } void dfs(int idex,int len,int cont,int num){ //idex表示开始搜索的下标,len表示当前在拼的边的长度, //num表示用过几个,cont表示拼好几个边了 int i; if(num == n && cont == number){ flag = true; return ; } if(len == 0){ for(i = 0;i < n; i++) if(!mark[i]) break; mark[i] = true; //用第i个 if(len + a[i] == ave) dfs(idex+1,0,cont+1,num+1); else dfs(i+1,a[i],cont,num+1); mark[i] = false; //回溯 return; } for(i = idex;i < n; i++){ if(i != 0 && !mark[i-1]&& a[i] == a[i-1]) continue;//前一根不选,相等的也不选 if(!mark[i] && len+a[i] <= ave){ mark[i] = true; if(len + a[i] == ave) dfs(i+1,0,cont+1,num+1); else dfs(i+1,len+a[i],cont,num+1); mark[i] = false; if(flag) return ; } } } int main(){ while(scanf("%d",&n),n){ sum = 0; int min = 0,cont = 0,k; for(int i = 0;i < n; ++i){ scanf("%d",&k); if(k > 50) continue; //ignore the stick which length is greater than 50 a[cont++] = k; sum += k; if(k > min) min = k; } if(cont > 0){ n = cont; sort(a,a+n,cmp); for(int i = min; i <= sum; i++){ flag = false; if(sum%i == 0){ //printf("%d/n",i); ave = i; number = sum/i; memset(mark,false,sizeof(mark)); dfs(0,0,0,0); if(flag) break; } } printf("%d/n",ave); } else printf("0/n"); } }

你可能感兴趣的:(【其他】)