AOJ 0120 - Patisserie

すこしbitDP書けるようになった.いままでループで,はじめてメモ化再帰書いた.
こっちのほうがいいかも.

Sは今まで使ったケーキ,vはさっき使ったケーキ
dp[S][v]は残りのケーキでできる最小幅.
全ケーキの幅になるよう最初に使ったケーキの半径と最後に使ったケーキの半径を足している.

#include<iostream>
#include<sstream>
#include<cmath>
#include<cstdio>

const int MAX_N = 12, INF = 1 << 16;
double dp[1 << MAX_N][MAX_N], rs[MAX_N];
int n;

inline double square(double d){
	return d * d;
}

double rec(int S, int v){
	if(dp[S][v] >= 0){
		return dp[S][v];
	}

	if(S == (1 << n) - 1){
		return rs[v];
	}

	double res = INF;
	for(int u=0;u<n;u++){
		if(!(S >> u & 1)){//未使用
			res = std::min(res, rec(S | (1 << u), u) + sqrt(square(rs[v]+rs[u]) - square(rs[v]-rs[u])));
		}
	}

	return dp[S][v] = res;
}

int main(){
	double box_l, min_l;
	while(std::cin >> box_l){
		if(std::cin.eof()){
			return 0;
		}

		min_l = INF;
		n = 0;

		std::string str;
		std::getline(std::cin, str);

		std::stringstream ss(str);
		while(!ss.eof()){
			int _i;
			ss >> _i;
			rs[n++] = _i;
			ss.ignore();
		}

		for(int i=0;i<n;i++){//iを始めにした最小幅をもとめる
			for(int j=0;j<(1<<MAX_N);j++){
				for(int k=0;k<MAX_N;k++){
					dp[j][k] = -1;
				}
			}

			min_l = std::min(min_l, rec(1 << i, i) + rs[i]);
		}

		if(min_l <= box_l){
			puts("OK");
		}else{
			puts("NA");
		}
	}
}