zoukankan      html  css  js  c++  java
  • 2019年7月训练(伍)


    P2831 愤怒的小鸟

    刚开始拿到这题,想着打个暴力。

    (0,0)和猪所在的点,至少两个点可以确定曲线 y=ax2+b中的a和b,然后把这条线和线上的点(也就是上面的猪)的vis[i]=1,避免重复。

     a,b计算式:(我知道大家很强,但我还是要提醒一下自己)

    打完交上去只有40分

    40分代码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define ll long long 
    using namespace std;
    
    int n,m,t;
    double x[20],y[20],old[500][5];
    
    double pa(double x1,double y1,double x2,double y2){
        return ((y1*x2-x1*y2)/((x1-x2)*x2*x1));
    }
    
    double pb(double a,double x1,double y1){
        return ((y1-a*x1*x1)/x1);
    }
    
    int main(){
        double a,b;
        scanf("%d",&t);
        while(t--){
            int maxn=0;
            int vis[20]={0};
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;i++){
                scanf("%lf%lf",&x[i],&y[i]);
            }
            for(int i=1;i<n;i++){
                for(int j=i+1;j<=n;j++){
                    if(x[i]==x[j]) continue;
                    a=pa(x[i],y[i],x[j],y[j]);
                    if(a>=0) continue;
                    b=pb(a,x[i],y[i]);
                    for(int k=1;k<=maxn;k++){
                        if(a==old[k][1]&&b==old[k][2]){
                            vis[i]=vis[j]=1;
                            break;
                        }
                    }
                    if(!vis[i]&&!vis[j]){
                        maxn++;
                        old[maxn][1]=a;
                        old[maxn][2]=b;
                        vis[i]=vis[j]=1;
                    }
                }
            }
            for(int i=1;i<=n;i++){
                if(!vis[i]) maxn++;
            }
            printf("%d
    ",maxn);
        }
        return 0;
    }
    View Code

    之后老老实实拿状压做了......

    对于每只猪考虑两种情况: 自己被单独打下来或者被其他抛物线经过打下来

    但是两点无法确定一条抛物线,也就是说这个抛物线可以自己设

    所以说一只鸟打下来一个猪一定可行

    但若能多打一只猪更好

    暴力找两只没被打下来(vis==0)的猪

     作抛物线,看看还能打下来几只

    不断更新dp。

    注意:

    1.预处理出所有抛物线能打几只猪, 可以省一维枚举每只猪,不然可能T掉

    2.此题卡精度, 判断两个浮点数是否相等可以确定一个精度然后去比,这题是1e-7?好像...


    AC码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define ll long long 
    using namespace std;
    
    template <class T>
    void read(T &x)
    {
        char c;
        bool op = 0;
        while(c = getchar(), c < '0' || c > '9')
            if(c == '-') op = 1;
        x = c - '0';
        while(c = getchar(), c >= '0' && c <= '9')
            x = x * 10 + c - '0';
        if(op) x = -x;
    }
    template <class T>
    void write(T x)
    {
        if(x < 0) putchar('-'), x = -x;
        if(x >= 10) write(x / 10);
        putchar('0' + x % 10);
    }
    
    int t,n,m;
    int dp[1<<18],old[210],tot=0;
    
    
    void work(double &a,double &b,double x1,double y1,double x2,double y2)
    {
        a=(x2*y1-x1*y2)/(x1*x2*(x1-x2));
        b=(x1*x1*y2-x2*x2*y1)/(x1*x2*(x1-x2));
    } 
    
    bool sa(double a,double b,double x,double y)
    {
        double abs=a*x*x+b*x-y;
        if(abs<0)
        abs= -abs;
        if(abs<0.000001)
        return true;
        else
        return false;
    }
    
    int ans()
    {
        dp[0] = 0;
        for(int i=0;i<=(1<<n)-1;i++)
        {
            for(int j=0;j<=tot-1;j++)
            {
                dp[i|old[j]]=min(dp[i|old[j]],dp[i]+1);
            }
        }
        return dp[(1<<n)-1];
    }
    
    int main()
    {
        read(t);
        while(t--)
        {
            memset(dp,0x3f,sizeof(dp));//我就是要写memset,作死
            tot=0;
            double x[20],y[20];
            read(n);read(m);
            for(int i=0;i<=n-1;i++)
            {
                scanf("%lf%lf",&x[i],&y[i]);
            }
            for(int i=0;i<=n-1;i++)
            {
                old[tot++]=(1<<i);
                for(int j=i+1,vis=0;j<n;j++)
                {
                    
                    if((vis>>j)&i!=0) continue;
                    else
                    {
                        double a,b;
                        work(a,b,x[i],y[i],x[j],y[j]);
                        if(a>=0) continue;
                        old[tot]=(1<<i);
                        for(int k=j;k<=n-1;k++)
                        {
                            if(sa(a,b,x[k],y[k]))
                            {
                                vis|=(1<<k);
                                old[tot]|=(1<<k);
                            }
                        }
                        tot++;
                    }
                }
            }
            printf("%d
    ",ans());
        }
        return 0;
    }

    2019-07-30 21:11:41

  • 相关阅读:
    ZendStudio 解决svn导出项目乱码问题
    Linux常用命令
    php类与对象
    Apache shutdown unexpectedly启动错误解决方法
    php构造函数和析构函数
    MySQL基本概念
    Javascript中常用事件的命名
    网页布局
    页面的自动滚动效果
    表单验证和事件(2)
  • 原文地址:https://www.cnblogs.com/plzplz/p/11272855.html
Copyright © 2011-2022 走看看