題意大概就是座標系上第一象限上有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指定的引數,且必...