1175:And Then. How Many Are There?
問題文
http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1175&lang=jp
ビットDPで解いた。
dp[ 残っている円盤 ] := その状態がありえるかどうか
checkは円盤同士が重なっているかを判定する関数。
i < j のとき円盤 j の上に円盤 i がある。
countは立っているビットの数を数える関数。
#include<iostream> #include<algorithm> #include<vector> #include<cmath> #include<cstdio> #define x first.first #define y first.second #define r second.first #define color second.second using namespace std; typedef pair<double,double> P; typedef pair<P,P> C; bool check(C a,C b){ return a.r+b.r>sqrt(pow(a.x-b.x,2)+pow(a.y-b.y,2)); } int count(int bits){ bits = (bits & 0x55555555) + (bits >> 1 & 0x55555555); bits = (bits & 0x33333333) + (bits >> 2 & 0x33333333); bits =(((bits >> 4) + bits) & 0x0f0f0f0f); bits += bits >> 8; return (bits + (bits >> 16)) & 0xff; } bool dp[(1<<25)]; int main(void){ int n; while(cin >> n,n){ C c[25]; for(int i=0;i<n;i++) scanf("%lf %lf %lf %lf",&c[i].x,&c[i].y,&c[i].r,&c[i].color); fill(dp,dp+(1<<n),false); dp[(1<<n)-1]=true; int ans=0; for(int S=(1<<n)-1;S>=0;S--){ if(!dp[S])continue; for(int i=0;i<n;i++){ for(int j=i+1;j<n;j++){ int nx=S; nx&=~(1<<i) & ~(1<<j); if(dp[nx])continue; if(!(S>>i&1) || !(S>>j&1))continue; if(c[i].color!=c[j].color)continue; bool fg=false; for(int k=0;k<n;k++){ if(!(S>>k&1))continue; fg|= k<i && check(c[i],c[k]); fg|= k<j && check(c[j],c[k]); if(fg)break; } if(!fg)dp[nx]|=dp[S]; } } if(dp[S])ans=max(ans,n-count(S)); } cout << ans << endl; } return 0; }