TopCoder SRM 379 Div1 Medium FillBox

問題

一辺が2^iの立方体がcubes[i]個ずつある。
これを使ってheight x width x lengthの直方体を埋めたい。
直方体は隙間なく立方体に埋められている必要があり、立方体が直方体からはみ出たり、立方体同士が重なったりしてはならない。


直方体を埋めるのに必要な立方体の数の最小値を求めよ。

制約条件

cubesの要素数≦20
length,width,height≦10^6
cubes[i]≦10^6

方針

greedyに埋めていくだけ。
少し実装を工夫しないと大変になるかも。

ソースコード

ll n,ans;
vi c;
bool rec(int x,int y,int z){
	int t[]={x,y,z};
	sort(t,t+3);
	x=t[0]; y=t[1]; z=t[2];
	if(x==0)return 1;
	
	for(int i=n-1;i>=0;i--)if(c[i]&&x>=1<<i){
		int p=x/(1<<i), q=y/(1<<i), r=z/(1<<i);
		ll t=(ll)p*q*r, s;
//できるだけ大きい立方体から使う。
//大きい立方体がなくなったら、一個小さい立方体8個を大きい立方体の代わりに。
		for(int j=i;j>=0;j--){
			s=min(t,c[j]);
			ans+=s;
			c[j]-=s;
			t-=s;
			t*=8;
		}
		
		int xx=p*(1<<i), yy=q*(1<<i), zz=r*(1<<i);
		if(t)return 0;
//直方体の残りの部分は7個に分割できる。7個について、再帰的に埋める。
//どれかで失敗したら、元の直方体を埋めることはできない。
		rep(j,1<<3)if(j<7&&!rec(j&1?xx:x-xx,j&2?yy:y-yy,j&4?zz:z-zz))return 0;
		return 1;
	}
	return 0;
}
class FillBox {
	public:
	int minCubes(int length, int width, int height, vector <int> cubes) 
	{
		n=cubes.size();
		c.clear(); rep(i,n)c.pb(cubes[i]);
		ans=0;
		if(rec(length,width,height))return ans;
		return -1;
	}
};