• 洛谷P2831 愤怒的小鸟——贪心?状压DP


    题目:https://www.luogu.org/problemnew/show/P2831

    一开始想 n^3 贪心来着;

    先按 x 排个序,那么第一个不就一定要打了么?

    在枚举后面某一个,和它形成一条抛物线,选能顺便打掉最多的那个;

    然后连样例都过不了...

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define eps 1e-9
    using namespace std;
    int T,n,m,ans;
    bool vis[20];
    struct N{
        double x,y;
    }p[20];
    bool cmp(N x,N y){return x.x<y.x;}
    int main()
    {
        scanf("%d",&T);
        while(T--)
        {
            memset(vis,0,sizeof vis);
            ans=0;
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;i++)
                scanf("%lf%lf",&p[i].x,&p[i].y);
            sort(p+1,p+n+1,cmp);
            for(int i=1;i<=n;i++)
            {
                if(vis[i])continue; vis[i]=1;
    //            printf("i=%d
    ",i);
                double x1=p[i].x, y1=p[i].y, xx=x1*x1, x2,y2,xy,a,b,aa=0,bb=0;
                for(int j=i+1;j<=n;j++)
                {
                    int cnt=1,mx=0;
                    if(vis[j]||p[j].x==p[i].x)continue;
                    x2=p[j].x; y2=p[j].y; xy=x2*x2;
    //                y2=y2/x2*x1; xy=xy/x2*x1;
    //                a=(y1-y2)/(xx-xy); 
                    a=(y1*x2-y2*x1)/(x1*x2*(x1-x2));
                    b=(y1-a*xx)/x1;
    //                printf("%lf %lf
    ",a,b);
                    for(int k=j+1;k<=n;k++)
                    {
                        if(vis[k])continue;
                        double tx=p[k].x,ty=p[k].y;
                        if(a*tx*tx+b*tx-ty<eps)cnt++;
                    }
                    if(cnt>mx)mx=cnt,aa=a,bb=b;
                }
                if(aa||bb)
                    for(int j=i+1;j<=n;j++)
                        if(fabs(aa*p[j].x*p[j].x+bb*p[j].x-p[j].y)<eps)vis[j]=1;
                ans++;
            }
            printf("%d
    ",ans);
        }
        return 0;
    }

    仔细想想,贪心可能是错的;

    正解是状压DP,DP真是与贪心相对的正确解法啊...

    n 很小,所以想到状压,记录所有可能的抛物线的打猪情况;

    然后类似背包转移即可...

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define eps 1e-8
    using namespace std;
    int T,n,m,f[262900],g[500],tot;
    double x[20],y[20];
    bool ck(int k,double a,double b)
    {
        return fabs(a*x[k]*x[k]+b*x[k]-y[k])<eps;
    }
    int main()
    {
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;i++)scanf("%lf%lf",&x[i],&y[i]);
            memset(g,0,sizeof g); double a,b;
            for(int i=1;i<=n;i++)
                for(int j=i+1;j<=n;j++)
                {
                    if(x[i]==x[j])continue;
                    a=(y[i]*x[j]-y[j]*x[i])/(x[i]*x[j]*(x[i]-x[j]));
                    b=(y[i]-a*x[i]*x[i])/x[i];
                    if(a>=0)continue;//>=而非> ! 
                    tot++;
                    for(int k=1;k<=n;k++)
                        if(ck(k,a,b))g[tot]|=(1<<(k-1));
                }
            for(int i=0;i<n;i++)g[++tot]|=(1<<i);
            sort(g+1,g+tot+1);
            tot=unique(g+1,g+tot+1)-g-1;
            memset(f,0x3f,sizeof f); f[0]=0;
            for(int i=0;i<(1<<n);i++)
                for(int j=1;j<=tot;j++)
                    f[i|g[j]]=min(f[i|g[j]],f[i]+1);
            printf("%d
    ",f[(1<<n)-1]);
        }
        return 0;
    }
  • 相关阅读:
    JQuery 判断某个属性是否存在 hasAttr
    微信支付开发-Senparc.Weixin.MP详解
    c# 两个数组比较,将重复部分去掉,返回不重复部分
    String.Format数字格式化输出 {0:N2} {0:D2} {0:C2
    asp.net 时间比较,常用于在某段时间进行操作
    关于C#正则表达式MatchCollection类的总结,正则表达式的应用
    开发错误11:Configuration with name ‘default’ not found
    Android新旧版本Notification
    Okio 1.9简单入门
    Android  PNG透明图片转JPG格式背景变黑
  • 原文地址:https://www.cnblogs.com/Zinn/p/9211030.html
Copyright © 2020-2023  润新知