土下座しながら探索中

主に競技プログラミング

UVa 11088 : End up with More Teams

UVa演習 2014/6/10 (火) 問3

問題リンク:http://uva.onlinejudge.org/external/110/11088.html

問題概要:
n人の人がいて、それぞれが30以下のパワーをもっている
その中から3人チームを何組か作りたい
チーム全体のパワーは20以上でなければならない
最大何チーム作れるだろうか

解法:
ビットDP
dp[どの人を使ったか][現在つくっているチームのパワー] := 最大人数
ビットの立っている数が2かどうかで場合分けする

コード:

#include<bits/stdc++.h>

#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)

using namespace std;

int dp[1<<15][21];
int bc[1<<15],a[15];

int main(){
  rep(i,(1<<15)) bc[i] = __builtin_popcount(i);
  int n,CNT=1;
  while( cin >> n , n ){
    rep(i,(1<<n)) rep(j,21) dp[i][j] = -1;
    dp[0][0] = 0;
    printf("Case %d: ",CNT++);
    rep(i,n) scanf("%d",a+i);
    sort(a,a+n);
    int maxi = 0;
    rep(bitmask,(1<<n)){
      bool phase = ((bc[bitmask]%3)==2);
      rep(i,21){
        if( dp[bitmask][i] < 0 ) continue;
        rep(j,n){
          if( (bitmask>>j) & 1 ) continue;
          int cost = i + a[j];
          if( phase ) {
            if( cost < 20 ) continue;
            dp[bitmask|(1<<j)][0] = max(dp[bitmask|(1<<j)][0],dp[bitmask][i]+1);
            maxi = max(maxi,dp[bitmask|(1<<j)][0]);
          } else {
            cost = min(cost,20);
            dp[bitmask|(1<<j)][cost] = max(dp[bitmask|(1<<j)][cost],dp[bitmask][i]);
          }
        }
      }
    }
    printf("%d\n",maxi);
  }
  return 0;
}