P2831 愤怒的小鸟

P2831 愤怒的小鸟

时隔n久,又回到了这道题。我还记得普及组时一头雾水的样子

题外话不扯,这道题是一道比较好的dp题

一眼就能看出来这是状态压缩。

状态压缩dp最大的特点是什么呢?(暴力)

我们需要暴力的枚举各种决策,然后转移

枚举决策是个很重要的思想。也是经常考察的知识点

所以需要多加练习

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using std::min;
double x[30],y[30];
int chance[301000],tot;
double eps=0.00000001;
int f[1<<(19)];
void calc(double &A,double &B,int i,int j)
{
    double a=y[i],b=x[i]*x[i],c=x[i];
    double d=y[j],e=x[j]*x[j],f=x[j];
    A=(a*f-c*d)/(b*f-c*e);
    B=(a*e-d*b)/(c*e-f*b);
    return ;
}
double abs(double a)
{
    if(a<0) return a*-1.0;
    return a;
}
bool get(double a,double b,int k)
{
    double c=a*x[k]*x[k]+b*x[k];
    if(abs(y[k]-c)<=eps)    
        return true;
    return false;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,m;
        tot=0;
        scanf("%d%d",&n,&m);//m好像在暴力面前并没有什么乱用
        for(int i=1;i<=n;i++)
            scanf("%lf%lf",&x[i],&y[i]);
        for(int i=1;i<=n;i++)
        {
            chance[++tot]=1<<(i-1);
            for(int j=i+1,vis=0;j<=n;j++)
            {
                double a,b;
                calc(a,b,i,j);//计算函数
                if(a>=0||vis&(1<<(j-1)))    continue;//符合现实,vis是用来去重,防止一次打掉多个的决策被重复枚举
                int pas=0;
                for(int k=1;k<=n;k++)
                    if(get(a,b,k)) //同时被打下
                    {
                        pas|=1<<(k-1);
                        vis|=1<<(k-1);  
                    }
                chance[++tot]=pas;
            }
        }
        memset(f,127,sizeof(f));
        f[0]=0;
        for(int i=0;i<(1<<n);i++)
            for(int j=1;j<=tot;j++)
                f[i|chance[j]]=min(f[i|chance[j]],f[i]+1);//转移
        printf("%d\n",f[(1<<n)-1]); 
    }
    
}

转载于:https://www.cnblogs.com/Lance1ot/p/9379446.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值