TopCoder SRM 346 Div1 Medium HeightRound
問題
n人の人がいて、それぞれの人の背の高さはheights[i]である。
このn人が円上に並ぶ。
隣り合う人同士の背の高さの差の絶対値の最大値を最小にしたい。
そのような並び順を出力せよ。
複数あるときは、辞書順で最も最初に来るものを出力せよ。
制約条件
n≦50
heights[i]≦1000
方針
円形に並べるので、最初の一人は一番背の低い人で固定でよい。
残りの部分について、差の絶対値の最大値をdとして、
d以下で人を並べられるかについて二分探索する。
人を並べられるかは、差がd以下の人のうち、最も大きい人を貪欲に使っていって、
最後に最初の一人とつながったときにその差がd以下ならよい。
dが求まったら、先頭から一人ずつ試していき、
上と同様の判定方法で、並び順があるかを見る。
並び順があったら、その人を使ってよい。
ソースコード
bool can(int d,vi &h,int s){ sort(h.begin()+s,h.end()); int n=h.size(), l=h[s-1]; bool use[50]={}; for(int i=s;i<n;i++){ for(int j=n-1;j>=s;j--)if(!use[j]&&abs(h[j]-l)<=d){ use[j]=1; l=h[j]; goto NEXT; } return 0; NEXT:; } return abs(h[0]-l)<=d; } class HeightRound { public: vector <int> getBestRound(vector <int> heights) { sort(all(heights)); int n=heights.size(); int lo=-1,hi=1000,mid; while(lo+1<hi){ mid=(lo+hi)/2; if(can(mid,heights,1))hi=mid; else lo=mid; } vi ans; ans.pb(heights[0]); rep(i,n-1){ for(int j=i+1;j<n;j++){ swap(heights[j],heights[i+1]); if(can(hi,heights,i+2)){ ans.pb(heights[i+1]); break; } swap(heights[j],heights[i+1]); } } return ans; } };