Description

Input



 

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
 

Data Constraint

首先暴力枚举即可获得75分,注意卡好精度,然而考场上写挂了,不开心
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
double x[20],y[20];
const double eps=1e-6;
int vis[20],ans,n,m;
void dfs(int a,int b)
{
    if(a>n) ans=min(ans,b);
    else
    {
        if(vis[a]) dfs(a+1,b);
        else
        {
            vis[a]=1;
            for(int i=a+1;i<=n;i++)
                if(!vis[i])
                {
                    double aa=(x[i]*y[a]-x[a]*y[i])/(x[a]*x[i]*x[a]-x[a]*x[i]*x[i]),bb=(x[i]*y[a]*x[i]-x[a]*x[a]*y[i])/(x[a]*x[i]*x[i]-x[a]*x[a]*x[i]);
                    if(aa>=0) continue;
                    for(int j=a+1;j<=n;j++)
                    {
                        double t=fabs(aa*x[j]*x[j]+bb*x[j]-y[j]);
                        if(t<eps)  vis[j]=1;
                    }
                    dfs(a+1,b+1);
                    for(int j=a+1;j<=n;j++)
                    {
                        double t=fabs(aa*x[j]*x[j]+bb*x[j]-y[j]);
                        if(t<eps)  vis[j]=0;
                    }
                }
            dfs(a+1,b+1);
            vis[a]=0;
        }
    }
    return;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        ans=20;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%lf%lf",&x[i],&y[i]);
        memset(vis,0,sizeof(vis));
        dfs(1,0);
        printf("%d\n",ans);
    }
    return 0;
}

接下来我们考虑提前算出n^2条抛物线,并且用一个2进制数来表示第i位表示以这个抛物线能否打到第i只鸟。然后用f[i]表示达到状态所需的最少抛物线数量。

f[i|zt[j]]=min(f[i]+1);zj[j]表示第j条抛物线对应的二进制数。时间复杂度(T*2^n*n^2)

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
double x[20],y[20];
const double eps=1e-6;
int ans,n,m,zt[405],f[1048580];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        ans=20;int bs=0,xd;
        memset(zt,0,sizeof(zt));
        scanf("%d%d",&n,&m);
        xd=(1<<n)-1;
        for(int i=1;i<=n;i++)
            scanf("%lf%lf",&x[i],&y[i]);
        for(int i=1;i<=n;++i)
            for(int j=1;j<=n;++j)
                if(i!=j)                
                {
                    double aa=(x[i]*y[j]-x[j]*y[i])/(x[j]*x[i]*x[j]-x[j]*x[i]*x[i]),bb=(x[i]*y[j]*x[i]-x[j]*x[j]*y[i])/(x[j]*x[i]*x[i]-x[j]*x[j]*x[i]);
                    if(aa<0)
                    {
                        ++bs;
                        for(int k=1;k<=n;++k)
                        {
                            double t=fabs(aa*x[k]*x[k]+bb*x[k]-y[k]);
                            if(t<eps)  zt[bs]+=1<<k-1;
                        }
                    }
                }
        memset(f,0x3f,sizeof(f));
        f[0]=0;
        for(int i=0;i<(1<<n);++i)
        {
            for(int j=1;j<=bs;++j)
                f[i|zt[j]]=min(f[i]+1,f[i|zt[j]]);
            for(int j=1,t=1;j<=n;t=1<<j,++j)
                f[i|t]=min(f[i]+1,f[i|t]);
        }
        printf("%d\n",f[xd]);
    }
    return 0;
}

现在我们来优化一下这个dp,然每次进行转移的抛物线必须覆盖第一个还未覆盖点(这个用vector记录即可),时间复杂度就被优化到了(T*2^n*n)

#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;
double x[20],y[20];
const double eps=1e-6;
int ans,n,m,zt[405],f[262145];
vector<int>fg[20];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        ans=20;int bs=0,xd;
        memset(zt,0,sizeof(zt));
        scanf("%d%d",&n,&m);
        xd=(1<<n)-1;
        for(int i=1;i<=n;i++)
            scanf("%lf%lf",&x[i],&y[i]),fg[i].clear();
        for(int i=1;i<=n;++i)
            for(int j=1;j<=n;++j)
                if(i!=j)                
                {
                    double aa=(x[i]*y[j]-x[j]*y[i])/(x[j]*x[i]*x[j]-x[j]*x[i]*x[i]),bb=(x[i]*y[j]*x[i]-x[j]*x[j]*y[i])/(x[j]*x[i]*x[i]-x[j]*x[j]*x[i]);
                    if(aa<0)
                    {
                        ++bs;
                        for(int k=1;k<=n;++k)
                        {
                            double t=fabs(aa*x[k]*x[k]+bb*x[k]-y[k]);
                            if(t<eps)  zt[bs]+=1<<k-1,fg[k].push_back(bs);
                        }
                    }
                }
        memset(f,0x3f,sizeof(f));
        f[0]=0;
        for(int i=0;i<xd;++i)
        {
            int w=1;
            for(int j=i;j&1;++w,j>>=1);
            f[i|1<<w-1]=min(f[i|1<<w-1],f[i]+1);
            int sl=fg[w].size();
            for(int j=0;j<sl;++j)
                f[i|zt[fg[w][j]]]=min(f[i]+1,f[i|zt[fg[w][j]]]);
        }
        printf("%d\n",f[xd]);
    }
    return 0;
}