愤怒的小鸟
(File IO): input:angrybirds.in output:angrybirds.out
Time Limits: 2s Memory Limits: 512MB
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
Hint
Data Constraint
Solution
对于每两只猪,只要他们的横坐标不一样,就会有一条经过原点的二次函数
y=ax2+bx
同时经过这两只猪,那么这时就是解二元一次方程的时候了,设第一只猪的坐标为(x1,y1),第二只猪的坐标为(x2,y2)
y1=ax12+bx1
y2=ax22+bx2
化为
b=y1−ax12x1=y2−ax22x2
a=y1−bx1x12=y2−bx2x22
得
x2y1−ax12x2=x1y2−ax22x1
y1x22−bx1x22=y2x12−bx2x12
移项合并同类项
(x12x2−x22x1)a=x2y1−x1y2
(x12x2−x22x1)b=y2x12−y1x22
可以得出a和b的式子
a=x2y1−x1y2x1x2(x1−x2)
b=y2x12−y1x22x1x2(x1−x2)
当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]);
}
}