1. 程式人生 > >【NOIP2016提高組day2】憤怒的小鳥

【NOIP2016提高組day2】憤怒的小鳥

span math cst clas 解析式 ++ amp -- memset

分析

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]);
    }
}

【NOIP2016提高組day2】憤怒的小鳥