VIJOS 2008 愤怒的小鸟

Posted on 2017-10-06 19:46  ziliuziliu  阅读(81)  评论(0编辑  收藏

先枚举两点 ,预处理这条抛物线能到达的所有点,随后状压dp。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 20
#define eps 1e-6
using namespace std;
int t,n,m,f[1<<maxn],tab[maxn][maxn];
double a,b;
struct pnt
{
    double x,y;
    pnt (double x,double y):x(x),y(y) {}
    pnt () {}
}p[maxn],r;
int sgn(double x)
{
    if (x<-eps) return -1;
    else if (x>eps) return 1;
    else return 0;
}
pnt calc(pnt x,pnt y)
{
    pnt ret;
    ret.y=(x.x*x.x*y.y-y.x*y.x*x.y)/(x.x*y.x*(x.x-y.x));
    ret.x=x.y/(x.x*x.x)-ret.y/x.x;
    return ret;
}
void pre_()
{
    for (register int i=0;i<(1<<n);i++) f[i]=100;
    memset(tab,0,sizeof(tab));
    for (register int i=0;i<=n-1;i++)
        for (register int j=i+1;j<=n-1;j++)
        {
            if (sgn(p[i].x-p[j].x)==0) continue;
            r=calc(p[i],p[j]);
            if (sgn(r.x)!=-1) continue;    
            for (register int k=0;k<=n-1;k++)
            {
                if (sgn(r.x*p[k].x*p[k].x+r.y*p[k].x-p[k].y)==0)
                    tab[i][j]|=(1<<k);
            }
        }
}
void dp_()
{
    f[0]=0;
    for (register int i=0;i<(1<<n);i++)
    {
        for (register int j=0;j<=n-1;j++)
            if (!((1<<j)&i))
            {
                for (register int k=j+1;k<=n-1;k++)
                    if (!((1<<k)&i))
                        f[i|tab[j][k]]=min(f[i|tab[j][k]],f[i]+1);
                f[i|(1<<j)]=min(f[i|(1<<j)],f[i]+1);
            }
    }
    printf("%d\n",f[(1<<n)-1]);
}
void work()
{
    scanf("%d%d",&n,&m);
    for (register int i=0;i<=n-1;i++)
    {
        scanf("%lf%lf",&a,&b);
        p[i]=pnt(a,b);
    }
    pre_();
    dp_(); 
}
int main()
{
    scanf("%d",&t);
    for (register int i=1;i<=t;i++) work();
    return 0;
}