解题思路: 每次取最大木棍和最小木棍比较,若相等,则所有木棍长度相等,完成;否则将最大木棍一分为二,更新最小木棍。重复直至完成。
木棍实现:用结构体保存木棍一分为二的两种可能(L为奇数时),每次取木棍时尽量取其中奇数木棍(奇数和偶数相差1,奇数一分为二后有的两种长度包含了偶数一分为二后的长度)。
#include<cstdio> #include<queue> using namespace std; const int INF = 1e9+1; struct stick {/*结构体保存每个木棍的可能*/ int l , r; /*运算符重载*/ bool operator <(const stick &s)const { if( l==s.l ) { return r<s.r; } return l<s.l; } bool operator ==(const stick &s)const { return ( (l==s.l) || (l==s.r) || (r==s.l) || (r==s.r) ); } }; int main() { int n,L; stick s,min_s;//min_s保存最小木棍 priority_queue<stick> que; //默认为大顶堆 每次取出最大木棍 min_s.l = min_s.r = INF; scanf("%d",&n); for( int i=0; i<n; i++ ) { scanf("%d",&L); s.l = s.r = L; if( s<min_s ) min_s = s; que.push(s); } int res = 0; while( true ) { s = que.top(); que.pop(); //每次取出最大木棍 if( min_s==s ) break; //所有木棍都一样长 退出 if( s.l&1 ) L = s.l;//(奇,偶);(奇,奇);(偶,奇);(偶,偶) else L = s.r;//(偶,偶)时相同,所以只在l为奇时取 /*最大木棍一分为二后的长度*/ if( L&1 ) { s.l = L/2; s.r = L/2+1; } else { s.l = s.r = L/2; } if( s<min_s ) min_s = s;//更新最小木棍 que.push(s); res++; } printf("%d\n",res); return 0; }