【NOIP2016提高组】 Day2 T3 愤怒的小鸟

题目传送门:https://www.luogu.org/problemnew/show/P2831

说个题外话:NOIP2014也有一道题叫做愤怒的小鸟。

这题自测时算错了eps,导致被卡了精度,从100卡剩80

由于此题n的范围特别小,所以考虑使用状压dp。

我们用一个整数i来描述状态,i的第k个bit表示第k只鸟是否被消灭,f[i]表示在这一状态下所需鸟的最小数量。

由于不在同一直线上的三个点确定一条抛物线,所以我们可以预处理出所有的可行抛物线,并确定在该抛物线上的鸟的编号(这一步对精度要求极高)。同时考虑到两只鸟与原点存在三点共线的情况,故在抛物线方案中写入单独消灭指定一只小鸟的情况。故消灭方案之多有(n*(n-1)/2+n)种。

然后就愉快地进行转移啦~ 顺便吐槽下m没有卵用

时间复杂度为O(n^2*2^n)。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #define M 18
 6 #define eps (1e-10)
 7 using namespace std;
 8 int f[1<<M]={0};
 9 int n;
10 struct pt{
11     int x,y; pt(){x=y=0;}
12     pt(double xx,double yy){x=xx; y=yy;}
13 }a[M];
14 struct pao{
15     double a,b; pao(){a=b=0;}
16     pao(pt A,pt B){
17         double x0=A.x,x1=B.x,y0=A.y,y1=B.y;
18         a=(y1-y0*x1/x0)/(x1*x1-x0*x1);
19         b=y0/x0-a*x0;
20     }
21     bool check(){
22         if(a>-eps) return 0;
23         return 1;
24     }
25     double get(double x){
26         double ans=a*x*x+b*x;
27         return ans;
28     }
29 };
30 int fly[M*M]={0},use=0;
31 bool b[1<<M]={0};
32 int Main(){
33     memset(f,1,sizeof(f));
34     memset(a,0,sizeof(a));
35     memset(fly,0,sizeof(fly));
36     memset(b,0,sizeof(b));
37     use=0; int m;
38     scanf("%d%d",&n,&m);
39     for(int i=1;i<=n;i++){
40         double x,y; scanf("%lf%lf",&x,&y);
41         x=x*100+0.3; y=y*100+0.3;
42         a[i]=pt(x,y);
43     }
44     for(int i=0;i<n;i++) fly[++use]=1<<i;
45     for(int i=1;i<=n;i++){
46         for(int j=1;j<i;j++) if(i!=j){
47             if(a[i].x==a[j].x) continue;
48             pao A=pao(a[i],a[j]);
49             if(!A.check()) continue;
50             int x=0;
51             for(int k=0;k<n;k++){
52                 double p=A.get(a[k+1].x);
53                 if(fabs(p-a[k+1].y)<=eps)
54                 x=x|(1<<k);
55             }
56             if(!b[x])
57             fly[++use]=x,b[x]=1;
58         }
59     }
60     int end=1<<n; f[0]=0;
61     for(int i=0;i<end;i++){
62         for(int j=1;j<=use;j++) 
63         f[i|fly[j]]=min(f[i|fly[j]],f[i]+1);
64     }
65     printf("%d\n",f[end-1]);
66 }
67 
68 int main(){
69     freopen("angrybirds.in","r",stdin);
70     freopen("angrybirds.out","w",stdout);
71     int cas; scanf("%d",&cas);
72     while(cas--) Main();
73     return 0;
74 }

 

posted @ 2017-10-24 20:19  AlphaInf  阅读(322)  评论(0编辑  收藏  举报