解いた問題のソースコードと解説など。


SRM 314 Div1 Medium GrasslandFencer

問題

フェンスが複数あり、それらの長さが与えられる。フェンスを使って三角形をいくつか作るとき、できた三角形の面積の総和を最大化せよ。ただし、複数のフェンスを使って1辺とすることや、1つのフェンスを複数に分割することはできない。

やりかた

bitDP。dp[S]:=(Sを使用したフェンスの集合とした時の面積の最大値)でDP。
関数内で、まだ使用していない3辺を指定して再帰をかける。

以下ソース。

double dp[1 << 20];

class GrasslandFencer {
public:
  int N;
  vector<int> f;
  double rec(int S){
    if((S + 1) >> N & 1) return 0.0;
    if(dp[S] >= 0.0) return dp[S];
    
    double tmp = 0.0;
    for(int i = 0; i < N; i++)
      for(int j = i + 1; j < N; j++)
	for(int k = j + 1; k < N; k++)
	  if(!(S >> i & 1) && !(S >> j & 1) && !(S >> k & 1)) //この3つは使用していない
	    tmp = max(tmp, 
		      area(f[i], f[j], f[k]) + rec(S | 1 << i | 1 << j | 1 << k));
    return dp[S] = max(dp[S], tmp);
  }
  double area(double a, double b, double c){
    if(a + b + c <= 2. * max(a, max(b, c))) return 0.0;
    double s = 0.5 * (a + b + c);
    return sqrt(s * (s - a) * (s - b) * (s - c));
  }
  double maximalFencedArea(vector <int> fences){
    N = fences.size();
    fill(dp, dp + (1 << 20), -1.0);
    f = fences;
    return rec(0);
  }
};
Get up! 明日のSUPER ST@R!