• NOIP2016 D2-T3 愤怒的小鸟


    看了题解之后知道,是状压dp。

    一、首先预处理一个$2^n$次方的fpow[]数组

    fpow[0]=1;
    for(Rint i=1;i<=19;i++)fpow[i]=(fpow[i-1]<<1);

    二、然后预处理一个sta[i][j],表示经过O,i,j三点的那条抛物线经过的所有的点的状态,处理时要注意:

    1、抛物线的$a$值大于等于0的要剔除

    2、横坐标相同的两点不可能在同一条抛物线上

    3、注意精度
    处理完后就可以状压dp了。

    三、dp时首先把dp[]值赋为inf

    方程:

    chkmin(dp[i|sta[J][K]],dp[i]+1)

    四、最后的优化:

    1、就是我们没有必要枚举所有的$i$,其实不论如何,在$dp[i]$中第一个没有出现的猪,我们最后一定要打的,所以我们干脆就只枚举最后那个猪,这样可以快一点

    2、找到第一只没打过的猪后,只需要枚举从它开始剩下的猪即可,不要从1开始:

    for(Rint k=j+1;k<=n;k++){//即此循环只需从j+1开始,而不需从1枚举到n
      int J=min(j,k),K=max(j,k);
      chkmin(dp[i|sta[J][K]],dp[i]+1);
    }

     五、Attention!(洛谷AC,UOJ WA)

    假如得了97分的话,估计是精度问题

    判断a的正负时要if(a<-1e-6)

    判断是否是同一解要if(Abs(...)<=1e-12)

    否则会炸extra test

    六、最后上AC代码:

    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #define Rint register int
    #define mem(a,b) memset(a,(b),sizeof(a))
    using namespace std;
    template<typename T>
    inline void read(T &x){
        x=0;T w=1,ch=getchar();
        while(!isdigit(ch)&&ch!='-')ch=getchar();
        if(ch=='-')w=-1,ch=getchar();
        while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar();
        x=x*w;
    }
    template<typename T>
    inline T Min(T &x,T &y){return x<y?x:y;}
    template<typename T>
    inline void chkmin(T &x,T y){if(y<x)x=y;}
    inline double Abs(double x){return x<0?-x:x;}
    
    const int maxn=23,inf=0x3f3f3f3f;
    const double eps=1e-12,eeps=-1e-6;
    int fpow[21];
    int n,m,sta[maxn][maxn],dp[1<<maxn];
    double x[maxn],y[maxn];
    inline void init(){
        n=0;
        m=0;
    }
    inline void update_sta(int a,int b){
        sta[a][b]=0;
        double x1=x[a],y1=y[a],x2=x[b],y2=y[b];
        if(x1==x2)return;
        double A=(y1*x2-y2*x1)/(x1*x1*x2-x2*x2*x1);
        if(A>=eeps)return;
        double B=(y1-A*x1*x1)/x1;
        for(Rint i=1;i<=n;i++)
            if(Abs(A*x[i]*x[i]+B*x[i]-y[i])<eps)
                sta[a][b]|=fpow[i-1];
    }
    int main(){
        fpow[0]=1;
        for(Rint i=1;i<=19;i++)fpow[i]=(fpow[i-1]<<1);
        int TT;
        read(TT);
        while(TT--){
            init();
            read(n);read(m);
            for(Rint i=1;i<=n;i++)scanf("%lf%lf",&x[i],&y[i]);
            for(Rint i=1;i<=n;i++)
                for(Rint j=i+1;j<=n;j++)
                    update_sta(i,j);
            for(Rint i=0;i<fpow[n];i++)dp[i]=inf;
            dp[0]=0;
            for(Rint i=0;i<fpow[n];i++){
                if(dp[i]==inf)continue;
                for(Rint j=1;j<=n;j++){
                    if(!(i&fpow[j-1])){
                        for(Rint k=j+1;k<=n;k++){
                            int J=min(j,k),K=max(j,k);
                            chkmin(dp[i|sta[J][K]],dp[i]+1);
                        }
                        chkmin(dp[i|fpow[j-1]],dp[i]+1);
                        break;
                    }
                }
            }
            printf("%d
    ",dp[fpow[n]-1]);
        }
        return 0;
    }
    AC代码
  • 相关阅读:
    Tarjan求LCA
    过滤器、监听器、拦截器的区别
    java操作Redis缓存设置过期时间
    Redis和Memcached区别,Redis的过期策略
    缓存穿透、缓存击穿、缓存雪崩区别和解决方案
    Memcached和Redis在Linux下的安装
    jmeter学习
    用FastDFS一步步搭建文件管理系统
    version control
    关于Linux的防火墙命令和端口占用查询
  • 原文地址:https://www.cnblogs.com/chinhhh/p/7749491.html
Copyright © 2020-2023  润新知