zoukankan      html  css  js  c++  java
  • [NOIP2016] 愤怒的小鸟 题解

    题面:

    题解:

    一看到n≤18,我们自然就会想到状压DP,设 f[i] 表示i的二进制表示下1已经打到的小猪与0还未打到的小猪所需要的最少小鸟数,答案就在 f[(1<<n)-1]里。
    再设S[i][j]其值的二进制下为1的表示i与j所形成的抛物线能够打到的小猪,0表示打不到的小猪。
    那么自然有:

    f[i|S[i][j]]=min(f[i|S[i][j],f[i]+1)

    考虑如何求出S[i][j],我们先枚举出i与j,判断i与j是否能构成一条抛物线。
    判断法则:

    1. 如果i与j横坐标相同的话,那就不可能构成一条抛物线。
    2. 由于抛物线都是形如y=ax2+bx的,所以我们带入i,j的横纵坐标,就得到一个二元一次方程组,用通式解出a,b然后再判断a是否小于0。

    然后枚举小猪k(1<=k<=n)的坐标,检验是否再抛物线上,若在则S[i][j]=S[i][j]&(1<<k-1)。

    优化:我们只需要找出这一个状态中还未被打到的最小的小猪,并用这个小猪去扩展其他点,因为反正最后都要打这一个点现在打了就好,防止以后重复多次去打这同一个点。

    附上代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const double eps=1e-8;
     4 int t,n,m,S[20][20],f[1<<20];
     5 double x[20],y[20];
     6 
     7 //解方程
     8 void equation(double &x,double &y,double a1,double b1,double c1,double a2,double b2,double c2){
     9     y=(a1*c2-a2*c1)/(a1*b2-a2*b1);
    10     x=(c1-b1*y)/a1;
    11 }
    12 
    13 int main(){
    14     for(scanf("%d",&t);t;t--){
    15     //初始化 
    16         memset(f,0x3f,sizeof(f));
    17         f[0]=0;
    18         scanf("%d %d",&n,&m);
    19         for(int i=1;i<=n;++i) scanf("%lf %lf",&x[i],&y[i]);
    20         //枚举两个小猪 
    21         for(int i=1;i<=n;++i){
    22             for(int j=1;j<=n;++j){
    23                 if(fabs(x[i]-x[j])<eps) continue;
    24                 double a,b;
    25                 equation(a,b,x[i]*x[i],x[i],y[i],x[j]*x[j],x[j],y[j]);
    26                 if(a>-eps) continue;
    27                 //枚举其他小猪
    28                 for(int k=1;k<=n;++k)
    29                     if(fabs(a*x[k]*x[k]+b*x[k]-y[k])<eps) S[i][j]|=(1<<(k-1));//判断是否在抛物线上
    30             }
    31         }
    32         //dp 
    33         for(int i=0;i<(1<<n);++i){
    34             //j表示第一个没有被打的小猪
    35             int j=0;
    36             for(j=1;j<=n-1;++j)
    37                 if(!(i&(1<<j-1))) break;
    38             f[i|(1<<(j-1))]=min(f[i|(1<<(j-1))],f[i]+1);//先单独转移,防止出现不与其他小猪构成抛物线的情况 
    39             for(int k=1;k<=n;++k) f[i|S[j][k]]=min(f[i|S[j][k]],f[i]+1);
    40         }
    41         printf("%d
    ",f[(1<<n)-1]);
    42     }
    43     return 0;
    44 }
  • 相关阅读:
    多线程对各种变量共享(经典)
    offsetHeight/Width clientHeight/Width scrollHeight/Width等高宽算法
    javascript基础-DOM原理
    放弃FreeMark?
    前端项目的开展
    【JAVA错误笔记】
    【JAVA错误笔记】
    【JAVA错误笔记】
    MVC Filter自定义异常(拦截)
    MVC Filter自定义验证(拦截)
  • 原文地址:https://www.cnblogs.com/Asika3912333/p/11366417.html
Copyright © 2011-2022 走看看