游戏题。我自己在写大式子转移,自己晕头转向。hzw提醒我先预处理所有在同一线上的猪。然后将所有可能出现的打架状态进行枚举转移。先忘了处理除数是0,挂了一个点。
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<math.h>
using namespace std;
const int maxn=(1<<20);
const double ex=1e-9;
int n,m,num,cnt;
int f[maxn],bir[maxn];//bir[],一只鸟可以打哪些猪
struct node{
double x,y;
}p[20];
node find(int i,int j){
node ans;
double X1=p[i].x,Y1=p[i].y,
X2=p[j].x,Y2=p[j].y;
if(fabs(X1-X2)<ex){ans.x=1;return ans;}
ans.x=(Y2-Y1*X2/X1)/(X2*X2-X1*X2); //除数要判0!!!
ans.y=Y1/X1-ans.x*X1;
return ans;
}
bool inlin(node l,node p){//点P是否在线l 上
double y=l.x*p.x*p.x+l.y*p.x;
if(fabs(y-p.y)<ex)return true;
return false;
}
void pre(){//处理1只鸟可以同时打哪些猪
for(int i=0;i<n;i++)
for(int j=i+1;j<n;j++){
node tmp;
tmp=find(i,j);
if(fabs(tmp.x)<ex)continue;
if(tmp.x>=0)continue ;//这两只猪没法一起打
bir[++cnt]=(1<<i)|(1<<j);
for(int k=j+1;k<n;k++)
if(inlin(tmp,p[k])){
bir[cnt]|=(1<<k);
}
}
}
int dp(){
memset(f,63,sizeof(f));
f[0]=0;
for(int i=0;i<num;i++)//1代表打了的猪,0代码没打
for(int j=0;j<=cnt;j++)
f[i|bir[j]]=min(f[i|bir[j]],f[i]+1);
return f[num-1];
}
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++){
scanf("%lf%lf",&p[i].x,&p[i].y);
bir[i]=(1<<i);
}
cnt=n-1;
num=(1<<n);
pre();
int tmp=dp();
printf("%d\n",tmp);
}
}