二刷提高课,题解目录在这里— 提高课的题解目录
我们求出所有关卡打到小猪的最少小鸟可以看出和m指令没有关系
此题目的状态设计是通过每个点的是否打到来进行设计的,
我们可以预处理出所有可能的抛物线,然后在这些抛物线中选取最少的数量覆盖所有猪
我们可以发现这其实就是最小重复覆盖问题
因为这一题数据量比较少用的状态压缩DP来做如果数据量大一些,只能用爆搜+减枝 参考:糖果
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int N=18,M=1<<N;
typedef pair<double ,double>PDD;
PDD q[N];
int pah[N][N];
int f[M];
int xd(double x,double y)
{
if(fabs(x-y)<1e-8)return 0;
if(x<y)return -1;
return 1;
}
int main()
{
int t;
cin>>t;
while(t--)
{
int n,m;
cin>>n>>m;
for(int i=0;i<n;i++)
{
double a,b;
cin>>a>>b;
q[i].first=a;
q[i].second=b;
}
memset(pah,0,sizeof pah);//对所有点的状态进行清零
for(int i=0;i<n;i++)
{
pah[i][i]=1<<i;
for(int j=0;j<n;j++)
{
double x1=q[i].first,y1=q[i].second;
double x2=q[j].first,y2=q[j].second;
if(!xd(x1,x2))continue;//横坐标不能相等
double a=(y1 / x1 - y2 / x2) / (x1 - x2);
double b=y1 / x1 - a * x1;
if(xd(a,0)>=0)continue;//a需要开口向下
int res=0;
for(int k=0;k<n;k++)
{
if(!xd(a*q[k].first*q[k].first+b*q[k].first,q[k].second))res+=1<<k;
}
//将这条抛物线能打到的猪装进状态中
pah[i][j]=res;
}
}
memset(f,0x3f,sizeof f);
f[0]=0;//没有点的初始化为零
for(int i=0;i+1<1<<n;i++)//全是1说明已经没有猪了
{
int re=0;
for(int j=0;j<n;j++)//随便取一个不含的点这里是第一个为零的点
{
if(!(i>>j&1))
{
re=j;
break;
}
}
for(int j=0;j<n;j++)
{
f[i|pah[re][j]]=min(f[i|pah[re][j]],f[i]+1);
//每一次都是选取最小的,看通过i状态所转换过来的是不是最小的
}
}
cout<<f[(1<<n)-1]<<endl;
}
return 0;
}