Description
乔治拿来一组等长的木棒,将它们随机地砍断,使得每一节木棍的长度都不超过50个长度单位。然后他又想把这些木棍恢复到为裁截前的状态,但忘记了初始时有多少木棒以及木棒的初始长度。请你设计一个程序,帮助乔治计算木棒的可能最小长度。每一节木棍的长度都用大于零的整数表示。
Input
输入包含多组数据,每组数据包括两行。第一行是一个不超过64的整数,表示砍断之后共有多少节木棍。第二行是截断以后,所得到的各节木棍的长度。在最后一组数据之后,是一个零。
Output
为每组数据,分别输出原始木棒的可能最小长度,每组数据占一行。
Sample Input
9
5 2 1 5 2 1 5 2 1
4
1 2 3 4
0
Sample Output
6
5
【思路】:bfs,太恶心了~各种优化
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<queue> #include<stack> #include<vector> #include<map> #include<string> #include<cstring> using namespace std; const int maxn=999999999; const int minn=-999999999; inline int read() { char c = getchar(); int x = 0, f = 1; while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); return x * f; } int N; int L; int length[3000]; int visit[65]; int i,j,k; int my_comp(int x,int y ) { return x>y; } int startNo,lastStickNo=-1; int dfs(int R, int M); int main() { while(1) { cin >> N; if( N == 0 ) break; int he= 0;/*记录总和*/ memset(length,0,sizeof(length)); for( int i = 0; i < N; i ++ ) { int n; cin >> length[i]; he+= length[i]; } sort(length,length+N, my_comp); for( L = length[0]; L <= he/ 2; L ++ ) { if( he% L) continue; memset( visit, 0,sizeof(visit)); if( dfs( N,L)) { cout << L << endl; break; } } if( L > he/ 2 ) cout << he<< endl; } return 0; } int dfs( int R, int M) { /*m表示当前正在拼接的木棍和我们枚举的长度L的差距*/ if( R == 0 && M == 0 ) return true; if( M==0 ) // 一根刚刚拼完的时候换新的一根 M=L; int start= 0; int startNo = 0; if( M != L ) //剪枝:不选第一个 startNo = lastStickNo + 1; for( int i = startNo; i < N; i ++) { if( !visit[i] && length[i] <= M) { if( i > 0 ) { if( visit[i-1] == 0 && length[i] == length[i-1]) continue; // 剪枝 如果某次拼接选择长度为S 的木棒,导致最失败,则在 同一位置尝试下一根木棒时,要跳过所有长度为S 的木棒 } visit[i] = 1; lastStickNo = i; if ( dfs( R - 1, M - length[i])) return true; else /*回溯*/ visit[i] = 0; if( M == L)//剪枝 return 0; } } return false; }