AOJ : 1175 - そして,いくつになった? (And Then. How Many Are There?)

問題概要

http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1175&lang=jp
日本語の問題文なので省略します.

アルゴリズム

bitDPで解けます.
それぞれの円盤を取り除いたか, まだ取り除いてないかをビットで管理します.
最大24枚しかないので, この方法で解くことができます.


DPを行うときは, 全ての円盤がある状態から順番に見ていきます.
それぞれの状態において, 消せる2枚の円盤のペアは消して, 全ての遷移パターンを試せばいいです.


あと, AOJでは, メモリ制限があるので, DPの配列をint型で管理してるとMLEしてしまうので気をつけてください.

プログラム

int n; //枚数
int x[25],y[25],r[25],c[25]; //円盤
int b[25]; //各円盤の上に重なっている円盤(ビット管理)

//円盤iと円盤jが重なっているかの判定
bool intersects(int i,int j){
  int dist1 = pow(x[i]-x[j],2) + pow(y[i]-y[j],2);
  int dist2 = pow(r[i]+r[j],2);

  return dist2 > dist1;
}

//DP用
char dp[1<<24];

int main(void){
  while(scanf("%d",&n),n){
    rep(i,n){
      scanf("%d%d%d%d",&x[i],&y[i],&r[i],&c[i]);

      //円盤iの上に重なっている円盤を全て探す
      b[i] = 0;
      rep(j,i) if(intersects(i,j)) b[i] |= (1<<j);
    }

    int ans = 0;
    int to = (1<<n);
    memset(dp,-1,sizeof(dp));
    dp[0] = 0;

    rep(i,to){
      if(dp[i] == -1) continue;

      ans = max(ans,(int)dp[i]);

      //消せる円盤のペア(j,k)を探す
      rep(j,n-1){
        //すでに円盤jは消えている or 円盤jの上の円盤が邪魔して消せない
        if((i & (1<<j)) != 0 || (i & b[j]) != b[j]) continue;

        REP(k,j+1,n){
          //jとkの色が違う or すでに円盤kは消えている or 円盤kの上の円盤が邪魔
          if(c[j] != c[k] || (i & (1<<k)) != 0 || (i & b[k]) != b[k]) continue;

          int next = i | (1<<j) | (1<<k); //next = 円盤jとkを消した状態(ビット管理)
          dp[next] = max((int)dp[next],dp[i]+2);
        }
      }
    }

    printf("%d\n",ans);
  }
}