• 【愤怒的小鸟】


    可怕的题目

    直接上代码了

    #include<cstring>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    #define eps (1e-6)
    #define re register
    #define min(a,b) ((a) < (b) ? (a) : (b))
    using namespace std;
    double x[21],y[21];
    double a,b;
    int d[21][21];
    int T,n,m;
    int f[262150],dp[262150];
    int ans;
    inline int check(int i,int j)
    {
        double t1=x[i]*x[i];
        double t2=x[j]*x[j];
        b=(t2*y[i]-y[j]*t1)/(x[i]*t2-x[j]*t1);
        a=(y[i]*x[j]-y[j]*x[i])/(t1*x[j]-t2*x[i]);
        if(a>-eps) return 0;
        return 1;
    }
    inline int pd(int k)
    {
        double yy=a*x[k]*x[k]+x[k]*b;
        if(yy+eps>y[k]&&yy-eps<y[k]) return 1;
        return 0;
    }
    inline void dfs (int k,int step)//k为当前的状态,step为所用的抛物线条数
    {
        if(dp[k]<=step) return;//如果当前到达这个状态再次之前有更优的解或相同的解,那么就不用往下搜了
        dp[k]=step;//记忆化dp[k]表示到k这个状态的最小抛物线数量
        if(step>=ans) return;
        if(k==(1<<n)-1)//到达终点
        {
            ans=min(ans,step);
            dp[k]=ans;
            return;
        }
        //我们额外枚举一条抛物线
        //我们枚举的这条抛物线必须能打到一只当前没有打到的猪
        //于是我们像树状数组里的lowbit操作一样,取出最靠后的那一只被打到的猪从它引出抛物线就行了
        //这是为什么呢,为什么在这一层搜索里没有必要将所有的抛物线都尝试一遍呢
        //其实很简单,因为就算这一层枚举出所有抛物线的情况,下一层也会枚举到的,于是就没有什么必要全部去枚举了
        int xx=((1<<n)-1)^k;
        xx=log2(xx&(-xx))+1;
        for (int j=1;j<=n;++j)
            dfs(k|d[xx][j],step+1);
    }
    int main()
    {
        scanf("%d",&T);
        while(T--)
        {
            memset(dp,20,sizeof(dp));
            memset(d,0,sizeof(d));
            scanf("%d%d",&n,&m);
            for(re int i=1;i<=n;i++)
                scanf("%lf%lf",&x[i],&y[i]);
            for(re int i=1;i<=n;i++)
            	d[i][i]=1<<(i-1);
            for(re int i=1;i<=n;i++)
            for(re int j=i+1;j<=n;j++)//枚举两只猪之后,再枚举其他猪看看这条抛物线是否能打到其他猪
            {
                int now=0;
                if(x[i]<x[j]+eps&&x[i]>x[j]-eps) continue;
                if(!check(i,j)) continue;
                now|=1<<(i-1);
                now|=1<<(j-1);
                for(re int k=1;k<=n;k++)
                if(k!=i&&k!=j&&pd(k)) now|=1<<(k-1);
                d[i][j]=d[j][i]=now;//d[i][j]表示i和j点之间的抛物线可以打到的猪的状态是什么
            }
            ans=9999;
            dfs(0,0);
            printf("%d
    ",ans);
        }
    }
    
  • 相关阅读:
    [Codevs 1230]元素查找(手写哈希表)
    bat+sqlcmd 批量执行脚本
    为Redmine的项目加上起止时间
    SDUT 1068-Number Steps(数学:直线)
    对象间的联动--观察者模式
    《千与千寻》给读者带来了什么?
    二叉树中和为某一值的路径
    关于Win8 用不了USB转串口驱动
    Android Socket编程学习笔记
    java中的正则操作总结
  • 原文地址:https://www.cnblogs.com/asuldb/p/10207813.html
Copyright © 2020-2023  润新知