NOIP 2016 愤怒的小鸟 题解
一道状压dp题,但是竟然可以搜索搜过!!(儒雅随和)。
代码(爆搜)
#include<bits/stdc++.h>
using namespace std;
const double eps=1e-8;
int T,n,m,ans;
double x[25],y[25],a[25],b[25];
bool book[25];
bool cheak(double a,double b){
return (fabs(a-b)<eps);
}
int clu(){
int tmp=0;
for(int i=1;i<=n;++i){
if(book[i]) tmp++;
}
return tmp;
}
void dfs(int c,int k){
if(k+clu()>=ans) return;
if(c>n){
ans=k+clu();
return;
}
bool flag=false;
for(int i=1;i<=k;++i){
if(cheak(a[i]*x[c]*x[c]+b[i]*x[c],y[c])){
flag=true;
dfs(c+1,k);
break;
}
}
if(!flag){
for(int i=1;i<=n;++i){
if(!cheak(x[i],x[c])&&book[i]){
double a1=(x[i]*y[c]-y[i]*x[c])/(x[c]*x[i]*(x[c]-x[i]));
double b1=(y[c]-x[c]*x[c]*a1)/x[c];
if(a1<0){
a[k+1]=a1;
b[k+1]=b1;
book[i]=0;
dfs(c+1,k+1);
book[i]=1;
}
}
}
book[c]=1;
dfs(c+1,k);
book[c]=0;
}
}
int main(){
scanf("%d",&T);
while(T--){
scanf("%d %d",&n,&m);
for(int i=1;i<=n;++i){
scanf("%lf %lf",&x[i],&y[i]);
}
memset(book,0,sizeof(book));
ans=n;
if(m==1) ans=n/3+2;
else if(m==2) ans=(2*n)/3+1;
dfs(1,0);
printf("%d\n",ans);
}
}
状压dp
#include<bits/stdc++.h>
using namespace std;
const double eps=1e-8;
int dp[262144],st[200],num;
double x[25],y[25];
int t,n,m;
bool cheak(double a,double b){
return fabs(a-b)<eps;
}
void init(){
memset(dp,0x3f,sizeof(dp));
memset(st,0,sizeof(st));
num=0;
dp[0]=0;
for(int i=1;i<=n;++i){
for(int j=i+1;j<=n;++j){
if(!cheak(x[i],x[j])){
double a1=(x[i]*y[j]-y[i]*x[j])/(x[i]*x[j]*(x[j]-x[i]));
double b1=(y[j]-a1*x[j]*x[j])/x[j];
if(a1<0){
++num;
for(int k=1;k<=n;++k){
if(cheak(a1*x[k]*x[k]+b1*x[k],y[k])){
st[num]|=(1<<(k-1));
}
}
}
}
}
}
}
void solve(){
init();
for(int s=0;s<(1<<n);++s){
for(int i=1;i<=num;++i) dp[s|st[i]]=min(dp[s|st[i]],dp[s]+1);
for(int i=1;i<=n;++i) dp[s|(1<<(i-1))]=min(dp[s|1<<(i-1)],dp[s]+1);
}
}
int main(){
scanf("%d",&t);
while(t--){
scanf("%d %d",&n,&m);
for(int i=1;i<=n;++i){
scanf("%lf %lf",&x[i],&y[i]);
}
solve();
printf("%d\n",dp[(1<<n)-1]);
}
return 0;
}