PKU 3925 Minimal Ratio Tree

問題

全ての辺と頂点に重みのついた、頂点数nの完全グラフが与えられる。
このグラフの部分木で頂点数がmのもののうちで、以下の値が最小になるようなものの頂点を小さい順に出力せよ。


Σ(部分木に含まれる頂点の重み)/Σ(部分木に含まれる頂点の重み)


複数ある場合は辞書順で最初に来るものを出力せよ。

制約条件

n≦15

方針

部分木の頂点の選び方は2^15通りしかないので全通り試せる。
頂点を決めたとき、その頂点からなるような部分木の「頂点の重みの和」の最小値はビットDPで計算できる。

ソースコード

int n,m, node[15],e[15][15];
int sum[1<<15], dp[1<<15];

int main()
{
	while(scanf("%d%d",&n,&m),n){
		rep(i,n)scanf("%d",node+i);
		rep(i,n)rep(j,n)scanf("%d",e[i]+j);
		
		rep(i,1<<n){
			dp[i]=inf;
			sum[i]=0;
			rep(j,n)if(i&1<<j)sum[i]+=node[j];
		}
		rep(i,n)dp[1<<i]=0;
		
		rep(i,1<<n)rep(j,n)if(i&1<<j)rep(k,n)if(!(i&1<<k))
			dp[i|1<<k]=min(dp[i|1<<k],dp[i]+e[j][k]);
		
		double mn=INF,tmp; int mni;
		for(int i=1;i<1<<n;i++){
			int bit=0;
			for(int j=i;j;j&=j-1)bit++;
			if(bit!=m)continue;
			
			tmp=dp[i]*1.0/sum[i];
			if(mn>tmp)mn=tmp, mni=i;
		}
		for(int i=0,j=0;i<n;i++)if(mni&1<<i)
			printf("%d%c",i+1,++j==m?'\n':' ');
	}
	return 0;
}