//这题又折腾了两天 心好累
//poj、hdu数据极弱,找虐请上uvalive
题意:给出n个数,将其分为任意份,每份里的数字和为同一个值。求每份里数字和可能的最小值。
解法:dfs+剪枝
1.按降序排序,长的木棍应该优先被使用
2.一个木棍一旦确定就不应当改变,因为新得到的木棍不会更优
3.如果当前循环扫到的第一根木棍加不进去直接return false 因为可以在后面的循环里被搜到
4.如果前一根等长的没有被使用那么不进入循环
5.份数要能整除总长度才会检查是否为合法解
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstring> 6 #include<cstdlib> 7 #include<queue> 8 #include<vector> 9 #include<map> 10 #include<stack> 11 #include<string> 12 13 using namespace std; 14 15 int n; 16 int crab[64]; 17 bool e[64]; 18 int MAX,tot_len,want_len; 19 20 bool cmp(int a,int b){ 21 return a>b; 22 } 23 24 bool dfs(int now,int p,int l){ 25 if (now*want_len==tot_len) return true; 26 for (int i=p;i<n;i++){ 27 if (e[i] && !(i>0 && e[i-1] && crab[i-1]==crab[i])){//剪枝4 28 if (l-crab[i]==0){ 29 e[i]=false; 30 if (dfs(now+1,0,want_len)) return true; 31 e[i]=true; 32 return false;//剪枝2 33 } 34 if (l-crab[i]>0){ 35 e[i]=false; 36 if (dfs(now,i+1,l-crab[i])) return true; 37 e[i]=true; 38 } 39 if (l==want_len) return false;//剪枝3 40 } 41 } 42 return false; 43 } 44 45 int main(){ 46 while (1){ 47 scanf("%d",&n); 48 if (n==0) return 0; 49 MAX=0; 50 tot_len=0; 51 for (int i=0;i<n;i++){ 52 scanf("%d",&crab[i]); 53 e[i]=1; 54 tot_len+=crab[i]; 55 MAX=max(MAX,crab[i]); 56 } 57 sort(crab,crab+n,cmp);//剪枝1 58 for (want_len=MAX;want_len<=tot_len;want_len++){ 59 if ((tot_len%want_len==0) && dfs(0,0,want_len)){//剪枝5 60 printf("%d ",want_len); 61 break; 62 } 63 } 64 } 65 return 0; 66 } 67 /* 68 4 69 4 3 2 1 70 71 9 72 5 2 1 5 2 1 5 2 1 73 4 74 1 2 3 4 75 0 76 */