歌名 - 歌手
0:00

    【NOIP2016提高组day2】愤怒的小鸟

    分析

    Kiana最近沉迷于一款神奇的游戏无法自拔。 简单来说,这款游戏是在一个平面上进行的。 有一架弹弓位于 (0, 0) 处,每次Kiana可以用它向第一象限发射一只红色的小鸟, 小鸟们的飞行轨迹均为形如 y = ax2 + bx 的曲线,其中 a, b 是Kiana指定的参数,且必须 满足 a < 0 。 当小鸟落回地面(即 x 轴)时,它就会瞬间消失。 在游戏的某个关卡里,平面的第一象限中有 n 只绿色的小猪,其中第 i 只小猪所在的坐标为 (xi, yi) 。 如果某只小鸟的飞行轨迹经过了 (xi, yi) ,那么第 i 只小猪就会被消灭掉,同时小鸟将会沿着原先的轨迹继续飞行; 如果一只小鸟的飞行轨迹没有经过 (xi, yi) ,那么这只小鸟飞行的全过程就不会对 第 i 只小猪产生任何影响。 例如,若两只小猪分别位于 (1, 3) 和 (3, 3) ,Kiana可以选择发射一只飞行轨迹为y = −x2 + 4x 的小鸟,这样两只小猪就会被这只小鸟一起消灭。 而这个游戏的目的,就是通过发射小鸟消灭所有的小猪。 这款神奇游戏的每个关卡对Kiana来说都很难,所以Kiana还输入了一些神秘的指令,使得自己能更轻松地完成这个游戏。 这些指令将在【输入格式】中详述。 假设这款游戏一共有 T 个关卡,现在Kiana想知道,对于每一个关卡,至少需要发射多少只小鸟才能消灭所有的小猪。 由于她不会算,所以希望由你告诉她。

    分析

    首先先求出每个点两两之间的函数解析式,并且求出这个解析式还能消灭那只猪。
    状压背包,
    \(f_s\)表示状态为s的最小值(其中s为二进制数,表示每只猪有没有被消灭)
    转移方程很简单\(f_{s|s`}=min(f_{s|s`},f_s+1)\)
    时间复杂度\(O(2^n·n^2)\)

    对了,注意精度

    #include <cmath>
    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    const int maxlongint=2147483647;
    const int mo=1000000007;
    const int N=550005;
    using namespace std;
    int f[N],b[20][20],n,m,t,d[500],mi[N];
    double a[N][2],a1,b1;
    int min1(int x,int y)
    {
    	return x>y?y:x;
    }
    int main()
    {
    	freopen("angrybirds.in","r",stdin);
    	freopen("angrybirds.out","w",stdout);
    	mi[0]=1;
    	for(int i=1;i<=20;i++)
    	{
    		mi[i]=mi[i-1]*2;
    	}
    	scanf("%d",&t);
    	for(;t--;)
    	{
    		scanf("%d%d",&n,&m);
    		memset(b,0,sizeof(b));
    		memset(f,43,sizeof(f));
    		f[0]=0;
    		for(int i=1;i<=n;i++)
    			scanf("%lf%lf",&a[i][0],&a[i][1]);
    		for(int i=1;i<=n;i++)
    		{
    			b[i][i]=mi[i-1];
    			for(int j=1;j<=n;j++)
    			if(i!=j)
    			{
    				double y=a[i][1],y1=a[j][1],x=a[i][0],x1=a[j][0],xx=a[i][0]*a[i][0],xx1=a[j][0]*a[j][0];
    				a1=b1=0;
    				y*=xx1;
    				x*=xx1;
    				y1*=xx;
    				x1*=xx;
    				y-=y1;
    				x-=x1;
    				b1=y/x;
    				a1=(a[i][1]-a[i][0]*b1)/(a[i][0]*a[i][0]);
    				if(a1>=0) continue;
    				b[i][j]=mi[i-1]+mi[j-1];
    				for(int k=1;k<=n;k++)
    				if(k!=i && k!=j)
    				{
    					if(a[k][1]-a[k][0]*a[k][0]*a1-a[k][0]*b1<=0.000000000001 && a[k][1]-a[k][0]*a[k][0]*a1-a[k][0]*b1>=-0.000000000001)
    					{
    						b[i][j]+=mi[k-1];
    					}
    				}
    			}
    		}
    		d[0]=0;
    		for(int i=1;i<=n;i++)
    			for(int j=1;j<=n;j++)
    			{
    				bool q=true;
    				if(f[b[i][j]]==1 || b[i][j]==0) continue;
    				for(int k=1;k<=n && q;k++)
    					for(int l=1;l<=n && q;l++)
    						if((b[i][j]&b[k][l])>=b[i][j] && b[i][j]!=b[k][l]) q=false;
    				if(q) d[++d[0]]=b[i][j],f[b[i][j]]=1;
    			}
    		for(int i=1;i<=d[0];i++)
    			for(int s=0;s<=mi[n]-1;s++)
    			{
    				f[s|d[i]]=min1(f[s|d[i]],f[s]+1);
    			}
    		printf("%d\n",f[mi[n]-1]);
    	}
    }
    
    
    
    posted @ 2018-05-21 12:16  无尽的蓝黄  阅读(166)  评论(0编辑  收藏  举报