愤怒的小鸟

9 篇文章 0 订阅
3 篇文章 0 订阅

愤怒的小鸟

(File IO): input:angrybirds.in output:angrybirds.out

Time Limits: 2s Memory Limits: 512MB

Description
Description
Input
Input
Output
Output
Sample Input
Sample Input1:

2
2 0
1.00 3.00
3.00 3.00
5 2
1.00 5.00
2.00 8.00
3.00 9.00
4.00 8.00
5.00 5.00

Sample Input2:

3
2 0
1.41 2.00
1.73 3.00
3 0
1.11 1.41
2.34 1.79
2.98 1.49
5 0
2.72 2.72
2.72 3.14
3.14 2.72
3.14 3.14
5.00 5.00

Sample Input3:

1
10 0
7.16 6.28
2.02 0.38
8.33 7.78
7.68 2.09
7.46 7.86
5.77 7.44
8.24 6.72
4.42 5.11
5.42 7.79
8.15 4.99

Sample Output
Sample Output1:

1
1

Sample Output2:

2
2
3

Sample Output3:

6

Hint
Hint
Data Constraint
Data


Solution


对于每两只猪,只要他们的横坐标不一样,就会有一条经过原点的二次函数 y=ax2+bx 同时经过这两只猪,那么这时就是解二元一次方程的时候了,设第一只猪的坐标为(x1,y1),第二只猪的坐标为(x2,y2)

y1=ax12+bx1
y2=ax22+bx2

化为
b=y1ax12x1=y2ax22x2
a=y1bx1x12=y2bx2x22


x2y1ax12x2=x1y2ax22x1
y1x22bx1x22=y2x12bx2x12

移项合并同类项
(x12x2x22x1)a=x2y1x1y2

(x12x2x22x1)b=y2x12y1x22

可以得出a和b的式子
a=x2y1x1y2x1x2(x1x2)
b=y2x12y1x22x1x2(x1x2)

当a<0时,此函数为过原点抛物线
当一堆猪满足,任意一对的a和b分别相等,才可以被一只鸟一次性射中。

很明显的状压dp:
设f[i][s] s为状态,i表示1~i都被选了,
对于一个集合P,里面的元素都被选中,i∈P,且满足要求,P里元素状态为k,f[i][s or k]=min(f[i][s or k],f[i-1][s]+1)

Codes

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int g[20][20],f[20][300000],n,t,m;
double a[20][2],d[20][20][2];

bool com(double x,double y)
{
    return(abs(x-y)<=1e-6);
}

void dfs(int lim,int v,int w)
{
    if(n<w)
    {
        if((v & ((1<<lim)-1))==((1<<lim)-1))f[lim][v]=min(f[lim][v],f[lim-1][v]);
        for(int i=lim;i<=n;i++)
        {
            int k=v | g[lim][i];
            f[lim][k]=min(f[lim][k],f[lim-1][v]+1);
        }
        return;
    }
    dfs(lim,v,w+1);
    dfs(lim,v+(1<<(w-1)),w+1);
}

int main()
{
    freopen("angrybirds.in","r",stdin);
    freopen("angrybirds.out","w",stdout);
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        memset(d,0,sizeof(d));
        memset(f,0x7f,sizeof(f));
        memset(g,0,sizeof(g));
        for(int i=1;i<=n;i++)
        {
            scanf("%lf%lf",&a[i][0],&a[i][1]);
            g[i][i]=1<<(i-1);
        }
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if(i!=j)
                {
                    double x1=a[i][0],y1=a[i][1],x2=a[j][0],y2=a[j][1];
                    if(x1!=x2)
                    {
                        d[i][j][0]=(y1*x2-x1*y2)/(x1*x2*(x1-x2));
                        d[i][j][1]=(x1*x1*y2-x2*x2*y1)/(x1*x2*(x1-x2));
                        if(d[i][j][0]<0)g[i][j]=(1<<(i-1))+(1<<(j-1));
                    }
                }
        for(int len=1;len<=n;len++)
            for(int i=1;i<=n-len+1;i++)
            {
                int j=i+len-1;
                if(d[i][j][0]<0)
                {
                    for(int k=i+1;k<j;k++)
                        if(com(d[i][j][0],d[i][k][0])&& com(d[i][j][1],d[i][k][1]))
                            g[i][j]=g[i][j] | g[i][k] | g[j][k];
                }
            }
        f[0][0]=0;
        for(int i=1;i<=n;i++)
        {
            dfs(i,(1<<(i-1))-1,i);
        }
        printf("%d\n",f[n][(1<<n)-1]);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值