Noip2016 憤怒的小鳥(狀壓DP)

2022-03-07 07:19:33 字數 1414 閱讀 3344

題意大概就是座標系上第一象限上有n只豬,每次可以構造一條經過原點且開口向下的拋物線,拋物線可能會經過某一或某些豬,求使所有豬被至少經過一次的拋物線最少數量。

原題中還有乙個特殊指令m,對於正解並沒有什麼卵用,

第一行乙個數t,表示資料組數

對於每組資料,第一行2個整數n,m,

接下來n行每行2個正實數想x,y表示第i只豬的座標

對於每組資料,輸出一行乙個數表示最少的拋物線數量

n<=18,t<=30

那麼n範圍只有18,可以想到狀壓dp,我們可以發現,2點確定一條拋物線y=ax^x+bx,可以開乙個二維陣列s[i][j]表示經過i點和j點的拋物線經過的豬的狀態,在二進位制下1表示經過,0表示沒有,這裡要注意精度問題,a>0的情況排除。

接下來用f[state]表示達到狀態state至少需要多少條拋物線,然後n^2得列舉每一條拋物線,狀態轉移方程為,

f[state|s[i][j]]=min,這裡有個細節優化很關鍵,就是第一次找到的豬轉移後直接break

因為如果繼續轉移後面的豬,後面也要射第乙個點,所以的轉移是多餘的,可以省下不少時間

#include #include #include #include #define inf 2139062143

#define n 24

using namespace std;

double x[n], y[n];

int t, n, m, f[1 << 19], s[n][n];

inline bool judge(double i, double j)

inline void work(int i, int j)

double a = (y[i] * x[j] - y[j] * x[i]) / (x[i] * x[j] * (x[i] - x[j]));

double b = y[i] / x[i] - (y[i] * x[j] - y[j] * x[i]) / (x[j] * (x[i] - x[j]));

if (a >= 0) return;

int ts = 0;

for (int g = 1; g <= n; ++g)

s[i][j] = ts;

}int main()

for (int i = 1; i <= n; ++i)

for (int j = 1; j <= n; ++j)

work(i, j);

f[0] = 0;

for (int i = 0; i < (1 << n) - 1; ++i)

for (int j = 1; j <= n; ++j)

break;

}printf("%d\n", f[(1 << n) - 1]);

} return 0;

}

然後就a了hahaha

NOIP2016 憤怒的小鳥(狀壓DP)

輸入格式 第一行包含乙個正整數 t,表示遊戲的關卡總數。下面依次輸入這 t個關卡的資訊。每個關卡第一行包含兩個非負整數 n,m,分別表示該關卡中的小豬數量和 kiana 輸入的神秘指令型別。接下來的 n行中,第 ii 行包含兩個正實數 如果 m 0,表示kiana輸入了乙個沒有任何作用的指令。如果 ...

NOIP 2016 憤怒的小鳥

題目描述 kiana最近沉迷於一款神奇的遊戲無法自拔。簡單來說,這款遊戲是在乙個平面上進行的。有一架彈弓位於 0,0 處,每次kiana可以用它向第一象限發射乙隻紅色的小鳥,小鳥們的飛行軌跡均為形如y ax 2 bx的曲線,其中a,b是kiana指定的引數,且必須滿足a 0。當小鳥落回地面 即x軸 ...

NOIP2016 憤怒的小鳥

時間限制 1 sec 記憶體限制 128 mb kiana最近沉迷於一款神奇的遊戲無法自拔。簡單來說,這款遊戲是在乙個平面上進行的。有一架彈弓位於 0,0 處,每次kiana可以用它向第一象限發射乙隻紅色的小鳥,小鳥們的飛行軌跡均為形如y ax 2 bx的曲線,其中a,b是kiana指定的引數,且必...