洛谷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\n",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\n",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\n",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\n",f[(1<<n)-1]);
    }
    return 0;
}
扫描二维码关注公众号,回复: 1685114 查看本文章

猜你喜欢

转载自www.cnblogs.com/Zinn/p/9211030.html