QAQ
状压DP
1表示小鸟打掉了,0表示没打掉。
dp[s]表示到S状态最少需要几步。
怎么枚举a,b。
因为c=0,只需两只猪即可确定一条曲线。
boom[i][j]表示i猪和j猪确定的曲线可以打掉的猪。
关于转移
枚举状态s中第一只没有打掉的小猪,固定i,枚举j即可
注意初始化
#include <cstdio>
#include <iostream>
#include <cstring>
#define ll long long
using namespace std;
const int maxm=(1<<19)+100;
const double limit=1e-7;
int boom[20][20];
double x[20],y[20];
int dp[maxm];
void init()
{
memset(dp,127/3,sizeof(dp));
memset(x,0,sizeof(x));
memset(y,0,sizeof(y));
memset(boom,0,sizeof(boom));
}
double fabs(double a)
{
if(a<0) return -a;
return a;
}
void work()
{
init();
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%lf%lf",&x[i],&y[i]);
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
boom[i][j]=0;
//boom[i][j]=(boom[i][j]|(1<<(i-1)));
//boom[i][j]=(boom[i][j]|(1<<(j-1)));
double f=x[i]*x[j]*(x[i]-x[j]);
double a=x[j]*y[i]-x[i]*y[j];
double b=x[i]*x[i]*y[j]-x[j]*x[j]*y[i];
if(a*f<0)//开口向下
{
for(int k=1;k<=n;k++)
if(fabs(a*x[k]*x[k]+b*x[k]-f*y[k])<limit) boom[i][j]|=1<<(k-1);
}
//boom[i][j]=~boom[i][j];
//boom[j][i]=boom[i][j];
}
}
dp[0]=0;
for(int i=0;i<=(1<<n)-1;i++)
{
int w=1;
while ((i>>(w-1))&1&&w<=n) w++;
dp[i|(1<<(w-1))]=min(dp[i]+1,dp[i|(1<<w-1)]);
for(int j=w+1;j<=n;j++)
if(i|boom[w][j]<=(1<<n)-1)
dp[i|boom[w][j]]=min(dp[i|boom[w][j]],dp[i]+1);
}
printf("%d\n",dp[(1<<n)-1]);
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
work();
}