LUOGU P2831 愤怒的小鸟 (NOIP 2016)

题面

题解

好像昨天wxl大爷讲的是O(Tn*2^n)的做法,后来没想通,就自己写了个O(Tn^2*2^n)的暴力状压,
莫名其妙过了??数量级二十亿??懵逼,可能到了CCF老爷机上就T了。dp[S]表示现在猪的状态,
然后枚举两只鸟,然后开炮。

代码

#include<bits/stdc++.h>

using namespace std;
const int MAXN = 18;
const int inf = 0x3f3f3f3f;
const double eps = 1e-6;     //精度

struct PIG{
    double x,y;
}p[20];

int cnt;
int n,m,T,S,pre;
int dp[1<<MAXN];
double a,b;

int main(){
    scanf("%d",&T);
    while(T--){
        memset(dp,0x3f,sizeof(dp));
        dp[0]=0;
        scanf("%d%d",&n,&m);
        for(register int i=1;i<=n;i++)
            scanf("%lf%lf",&p[i].x,&p[i].y);
        for(register int i=0;i<((1<<n)-1);i++){
            S=0;a=0;b=0;pre=0;
            if(dp[i]==inf) continue;
            for(register int j=1;j<=n;j++){
                S=0;pre=0;a=0;b=0;
                if((i&(1<<(j-1)))==0){
                    S|=(1<<(j-1));
                    pre=j;
                }
                if(!pre) continue;
                for(register int k=1;k<=n;k++)
                    if((i&(1<<(k-1)))==0 && k!=j)
                        if(p[pre].x!=p[k].x){
                        a=p[pre].y*p[k].x/p[pre].x-p[k].y;  //二次函数表达式,很好推
                        a/=(p[pre].x*p[k].x-p[k].x*p[k].x);
                        if(a>=0) continue;
                        else{
                            b=(p[pre].y-a*p[pre].x*p[pre].x)/p[pre].x;
                            break;
                        }
                    }
                if(a<0)
                    for(register int j=1;j<=n;j++)   //看是否能打到更多的鸟
                        if(fabs(a*p[j].x*p[j].x+b*p[j].x-p[j].y)<=eps && j!=pre)
                            S|=(1<<(j-1));
                dp[S|i]=min(dp[S|i],dp[i]+1);
            }
        }
        printf("%d\n",dp[(1<<n)-1]);
    }
}

猜你喜欢

转载自blog.csdn.net/qq_40448823/article/details/80732006