Skip to content

集合式状压dp ​

题意:
给定多个点,问至少有多少条开口向下的抛物线能将这些点完全覆盖
思路:
预处理出 $ n^2 $ 条抛物线,将该抛物线能覆盖到的点用状压表示,然后状态转移

cpp
int f[M];
int path[N][N],n,m;
double X[N],Y[N];
int cmp(double x,double y){
    if(fabs(x-y)<eps)return 0;
    if(x>y)return 1;
    return -1;
}
void solve(){
    cin>>n>>m;
    for(int i=0;i<n;i++)cin>>X[i]>>Y[i];
    memset(path,0,sizeof path);
    for(int i=0;i<n;i++){
        path[i][i]=1<<i;
        for(int j=0;j<n;j++){
            if(!cmp(X[i],X[j]))continue;
            double a=(Y[i]/X[i]-Y[j]/X[j])/(X[i]-X[j]);
            double b=Y[i]/X[i]-a*X[i];
            if(a>0)continue;
            int state=0;
            for(int k=0;k<n;k++){
                double x=X[k],y=Y[k];
                if(!cmp(a*x*x+b*x,y))state+=1<<k;
            }
            path[i][j]=state;
        }
    }
    memset(f,0x3f,sizeof f);
    f[0]=0;
    for(int i=0;i+1<1<<n;i++){
        int x=0;
        for(int j=0;j<n;j++){
            if(!(i>>j&1)){
                x=j;
                break;
            }
        }
        for(int j=0;j<n;j++){
            f[i|path[x][j]]=min(f[i|path[x][j]],f[i]+1);
        }
    }
    cout<<f[(1<<n)-1]<<"\n";
}