[LOJ] #2363「NOIP2016」愤怒的小鸟

精度卡了一个点,别人自带大常数,我自带大浮点误差qwq.

听了好几遍,一直没动手写一写。

f[S]表示S集合中的猪被打死的最少抛物线数,转移时考虑枚举两个点,最低位的0为第一个点,枚举第二个点,构造一条抛物线。

检查这条抛物线能否“顺便”打死更多的猪,然后转移即可。

注意存在一种情况,只剩下一个点,这时候要给最低位0单独开一条抛物线(体现在代码里就是f[i|(1<<(st-1))]单独转移一次)

 

//失误 这是一个
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>

using namespace std;
typedef long double db;

const int MAXN=19;
const db eps=1e-9;

inline void calc(db x1,db y1,db x2,db y2,db &a,db &b){
  a=(db)1.0*(x1*y2-x2*y1)/(x1*x2*(x2-x1));
  b=(db)1.0*(x1*x1*y2-x2*x2*y1)/(x1*x2*(x1-x2));
}
inline db F(db a,db b,db x){return (db)1.0*a*x*x+1.0*b*x;}
inline bool equal(db x,db y){return fabs(x-y)<=eps;}

int n,useless;

db px[MAXN],py[MAXN];
int f[1<<MAXN];

void solve(){
  scanf("%d%d",&n,&useless);
  memset(f,0x7f,sizeof(f));
  f[0]=0;
  for(int i=1;i<=n;i++) scanf("%Lf%Lf",&px[i],&py[i]);
  int st=0;db u,v;
  for(int i=0;i<(1<<n);i++){
    for(st=1;st<=n;st++)if(!((1<<(st-1))&i))break;
    f[i|(1<<(st-1))]=min(f[i|(1<<(st-1))],f[i]+1);
    for(int j=st+1;j<=n;j++){
      if((1<<(j-1))&i) continue;
      int tmp=i|(1<<(st-1));
      calc(px[st],py[st],px[j],py[j],u,v);
      if(u>=0) continue;
      tmp|=(1<<(j-1));
      for(int k=1;k<=n;k++){
        if(k==j||k==st) continue;
        if(i&(1<<(k-1))) continue;
        if(equal(F(u,v,px[k]),py[k])) tmp|=(1<<(k-1));
      }
      f[tmp]=min(f[tmp],f[i]+1);
    }
  }
  cout<<f[(1<<n)-1]<<endl;
}

int main(){
  int T;
  scanf("%d",&T);
  while(T--) solve();
  return 0;
}

 

posted @ 2018-07-17 20:38  GhostCai  阅读(135)  评论(2编辑  收藏  举报