TopCoder SRM 316 Div1 Medium PlacingPieces
問題
n個の幅の等しい長方形があり、それぞれの長さはpieces[i]である。
この長方形を、幅の等しい、長さがLの長方形の中に入れる。
中の長方形は重なったり、外にはみでていたりしてはならない。
中の長方形を、「他の使っていない長方形をどこにも追加することができない」ように並べる。
中にいれる長方形の数の最小値を求めよ。
制約条件
n≦30
pieces[i]≦100
L≦1000
方針
総当たり+ナップサック。
長さがpieces[s]未満の長方形を全て使うとき、
長方形と長方形の間隔は0〜pieces[s]未満にできる。
dp[i]を、長さiの地点まで長方形を並べるときの、長方形の数の最小値とする、
ナップサック問題のような動的計画法により、
このときの最小値が求まる。
ただし、整数でない座標に長方形を置くこともできるので、少し工夫が必要。
全部の間隔がpieces[s]ぴったりだとダメで、pieces[s]-EPSならよい。
dp[i][j]を、j=1ならpieces[s]より小さい間隔があったときのiの個数の最小値、
j=0ならpieces[s]より小さい間隔がまだないときのiの個数の最小値とする。
ソースコード
vi len; int l,n,dp[1001][2]; int solve(int s){ rep(i,l+1)rep(j,2)dp[i][j]=inf; int sum=0, cnt=0; rep(i,n)if(len[i]<len[s])sum+=len[i], cnt++; if(sum>l)return inf; for(int i=sum;i<=l&&i<=sum+cnt*len[s];i++) dp[i][i<sum+cnt*len[s]]=cnt; rep(i,n)if(len[i]>=len[s]){ for(int j=l;j>=0;j--)rep(k,2)if(dp[j][k]!=inf){ if(j+len[i]>l)continue; rep(sp,len[s]+1){ int nj=j+sp+len[i], nk=k||sp<len[s]; nj=min(nj,l); dp[nj][nk]=min(dp[nj][nk],dp[j][k]+1); } } } int res=inf; for(int i=max(0,l-len[s]);i<=l;i++){ res=min(res,dp[i][1]); if(i>l-len[s])res=min(res,dp[i][0]); } return res; } class PlacingPieces { public: int optimalPlacement(int L, vector <int> pieces) { len=pieces; n=len.size(); l=L; int ans=n; rep(s,n)ans=min(ans,solve(s)); return ans; } };