• 【Luogu】P2831愤怒的小鸟(手算抛物线+状压DP)


      题目链接

      设f[s]表示二进制集合表示下的s集合都打掉用了多少小鸟。

      预处理出lne[i][j]表示i、j确定的抛物线能打掉的小鸟集合。

      于是就有f[s|lne[i][j]]=min(f[s|lne[i][j]],f[s]+1);

      什么?两个点确定不了抛物线?原点是不是被忘掉了……

      代码如下

     

    #include<cstdio>
    #include<cctype>
    #include<cmath>
    #include<iostream>
    #include<cstring>
    using namespace std;
    double x[1000],y[1000];
    int lne[1000][1000];
    int f[800000];
    
    int main(){
        int T;
        cin>>T;
        while(T--){
            int n,m;
            cin>>n>>m;
            memset(lne,0,sizeof(lne));
            memset(f,127,sizeof(f));
            for(int i=1;i<=n;++i)    cin>>x[i]>>y[i];
            for(int i=1;i<=n;++i)
                for(int j=1;j<=n;++j){
                    if(i==j)    continue;
                    double d=y[j]-(y[i]/x[i]*x[j]),c=x[j]*(x[j]-x[i]);
                    double a=d/c,b=(y[i]-x[i]*x[i]*a)/x[i];
                    if(a<0)
                        for(int k=1;k<=n;++k)
                            if(abs(x[k]*x[k]*a+x[k]*b-y[k])<=1e-7)    lne[i][j]|=(1<<(k-1));
                }
            int Max=(1<<n)-1;
            for(int i=1;i<=n;++i)    f[1<<(i-1)]=1;
            f[0]=0;
            for(int i=0;i<=Max;++i){
                int pos=1;
                while(i>>(pos-1)&1)    ++pos;
                if(f[i|(1<<(pos-1))]>f[i]+1)    f[i|(1<<(pos-1))]=f[i]+1;
                for(int j=pos+1;j<=n;++j)
                    f[i|lne[pos][j]]=min(f[i|lne[pos][j]],f[i]+1);
            }
            printf("%d
    ",f[Max]);
        }
        return 0;
    }
  • 相关阅读:
    Hibernate
    Redis的学习
    Redis的人门以及使用
    Win32 配置文件用法
    Using virtual lists
    windows log
    Win查询注册表获取CPU与内存参数
    MFC 多线程及线程同步
    使用Custom Draw优雅的实现ListCtrl的重绘
    MFC工具栏设计
  • 原文地址:https://www.cnblogs.com/cellular-automaton/p/7641630.html
Copyright © 2020-2023  润新知