【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]); } }
【NOIP2016提高組day2】憤怒的小鳥