P4242【NOIP2016 DAY2】愤怒的小鸟

这里写图片描述
输入格式
这里写图片描述
输出格式
对每个关卡依次输出一行答案。
输出的每一行包含一个正整数,表示相应的关卡中,消灭所有小猪最少需要的小鸟数量。

题解

状压dp
先两两枚举鸟坐标求出抛物线表达式并枚举可击杀数量,将其视作一个商品存入,然后背包dp。

注意精度 用rep来限制精度查

代码

#include<stdio.h> 
#include<algorithm> 
#include<queue> 
#include<cmath> 
#include<cstdio> 
#include<iostream> 
#include<cstring> 
using namespace std; 
#define maxn 20 
#define maxn1 270001 
#define maxn2 500 
#define inf 1e9 
const double rep=1e-7; 
struct node{ 
        double x,y; 
}; 
node pos[maxn]; 
int v[maxn2],f[maxn1]; 
int t,n,m; 
int full; 
int num,mc,cnt; 
void work() 
{ 
        int i,j,m; 
        double a,b; 
        cnt=0; 
        for(i=1;i<=n;i++) 
        { 
                for(j=i+1;j<=n;j++) 
                {  

                    double x1,x2,y1,y2; 
                    x1=pos[i].x;y1=pos[i].y; 
                    x2=pos[j].x;y2=pos[j].y;
                    a=(y1*x2-y2*x1)/(x2*x1)/(x1-x2);
                    if(a>=0) continue;
                    b=y1/x1-a*x1; 
                    int val=0;
                    cnt++; 
                    for(m=1;m<=n;m++){ 
                            if(fabs(a*pos[m].x*pos[m].x+b*pos[m].x-pos[m].y)<=rep){ 
                                    val|=(1<<(m-1)); 
                            }

                    }

                     v[cnt]=val;

                } 
        } 
        for(i=1;i<=n;i++){ 
                v[++cnt]=1<<(i-1); 
        } 
} 
void dp() 
{ 
        int i,j,k; 
        int ful=((1<<n)-1); 
        for(i=1;i<=ful;i++) f[i]=inf; 
        f[0]=0;
        for(i=1;i<=cnt;i++) 
        { 
                for(j=0;j<=ful;j++) 
                { 
                        if(f[j]!=inf){ 
                                f[j|v[i]]=min(f[j|v[i]],f[j]+1); 
                        } 
                } 
        } 
} 
int main() 
{ 
        int i,j; 
        scanf("%d",&t); 
        while(t--) 
        { 
                scanf("%d%d",&n,&m);  
                for(i=1;i<=n;i++) scanf("%lf%lf",&pos[i].x,&pos[i].y); 
                work(); 
                dp(); 
                cout<<f[(1<<n)-1]<<endl; 
        } 
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值