https://i.loli.net/2019/07/25/5d39b5315c60935716.jpg

2019年7月训练(伍)


P2831 愤怒的小鸟

刚开始拿到这题,想着打个暴力。

(0,0)和猪所在的点,至少两个点可以确定曲线 y=ax2+b中的a和b,然后把这条线和线上的点(也就是上面的猪)的vis[i]=1,避免重复。

 a,b计算式:(我知道大家很强,但我还是要提醒一下自己)

 

 

打完交上去只有40分

40分代码:

 

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long 
using namespace std;

int n,m,t;
double x[20],y[20],old[500][5];

double pa(double x1,double y1,double x2,double y2){
    return ((y1*x2-x1*y2)/((x1-x2)*x2*x1));
}

double pb(double a,double x1,double y1){
    return ((y1-a*x1*x1)/x1);
}

int main(){
    double a,b;
    scanf("%d",&t);
    while(t--){
        int maxn=0;
        int vis[20]={0};
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%lf%lf",&x[i],&y[i]);
        }
        for(int i=1;i<n;i++){
            for(int j=i+1;j<=n;j++){
                if(x[i]==x[j]) continue;
                a=pa(x[i],y[i],x[j],y[j]);
                if(a>=0) continue;
                b=pb(a,x[i],y[i]);
                for(int k=1;k<=maxn;k++){
                    if(a==old[k][1]&&b==old[k][2]){
                        vis[i]=vis[j]=1;
                        break;
                    }
                }
                if(!vis[i]&&!vis[j]){
                    maxn++;
                    old[maxn][1]=a;
                    old[maxn][2]=b;
                    vis[i]=vis[j]=1;
                }
            }
        }
        for(int i=1;i<=n;i++){
            if(!vis[i]) maxn++;
        }
        printf("%d\n",maxn);
    }
    return 0;
}
View Code

 


之后老老实实拿状压做了......

对于每只猪考虑两种情况: 自己被单独打下来或者被其他抛物线经过打下来

但是两点无法确定一条抛物线,也就是说这个抛物线可以自己设

所以说一只鸟打下来一个猪一定可行

但若能多打一只猪更好

暴力找两只没被打下来(vis==0)的猪

 作抛物线,看看还能打下来几只

不断更新dp。

注意:

1.预处理出所有抛物线能打几只猪, 可以省一维枚举每只猪,不然可能T掉

2.此题卡精度, 判断两个浮点数是否相等可以确定一个精度然后去比,这题是1e-7?好像...


AC码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long 
using namespace std;

template <class T>
void read(T &x)
{
    char c;
    bool op = 0;
    while(c = getchar(), c < '0' || c > '9')
        if(c == '-') op = 1;
    x = c - '0';
    while(c = getchar(), c >= '0' && c <= '9')
        x = x * 10 + c - '0';
    if(op) x = -x;
}
template <class T>
void write(T x)
{
    if(x < 0) putchar('-'), x = -x;
    if(x >= 10) write(x / 10);
    putchar('0' + x % 10);
}

int t,n,m;
int dp[1<<18],old[210],tot=0;


void work(double &a,double &b,double x1,double y1,double x2,double y2)
{
    a=(x2*y1-x1*y2)/(x1*x2*(x1-x2));
    b=(x1*x1*y2-x2*x2*y1)/(x1*x2*(x1-x2));
} 

bool sa(double a,double b,double x,double y)
{
    double abs=a*x*x+b*x-y;
    if(abs<0)
    abs= -abs;
    if(abs<0.000001)
    return true;
    else
    return false;
}

int ans()
{
    dp[0] = 0;
    for(int i=0;i<=(1<<n)-1;i++)
    {
        for(int j=0;j<=tot-1;j++)
        {
            dp[i|old[j]]=min(dp[i|old[j]],dp[i]+1);
        }
    }
    return dp[(1<<n)-1];
}

int main()
{
    read(t);
    while(t--)
    {
        memset(dp,0x3f,sizeof(dp));//我就是要写memset,作死
        tot=0;
        double x[20],y[20];
        read(n);read(m);
        for(int i=0;i<=n-1;i++)
        {
            scanf("%lf%lf",&x[i],&y[i]);
        }
        for(int i=0;i<=n-1;i++)
        {
            old[tot++]=(1<<i);
            for(int j=i+1,vis=0;j<n;j++)
            {
                
                if((vis>>j)&i!=0) continue;
                else
                {
                    double a,b;
                    work(a,b,x[i],y[i],x[j],y[j]);
                    if(a>=0) continue;
                    old[tot]=(1<<i);
                    for(int k=j;k<=n-1;k++)
                    {
                        if(sa(a,b,x[k],y[k]))
                        {
                            vis|=(1<<k);
                            old[tot]|=(1<<k);
                        }
                    }
                    tot++;
                }
            }
        }
        printf("%d\n",ans());
    }
    return 0;
}

2019-07-30 21:11:41

 

posted @ 2019-07-30 21:19  plzplz  阅读(125)  评论(0编辑  收藏  举报
https://i.loli.net/2019/07/25/5d39c1d4c249939054.jpg