1. 程式人生 > >【洛谷】【堆+貪心】P1484 種樹

【洛谷】【堆+貪心】P1484 種樹

isp queue while std using pen mil OS 一條直線

【題目描述:】

cyrcyr今天在種樹,他在一條直線上挖了n個坑。這n個坑都可以種樹,但為了保證每一棵樹都有充足的養料,cyrcyr不會在相鄰的兩個坑中種樹。而且由於cyrcyr的樹種不夠,他至多會種k棵樹。假設cyrcyr有某種神能力,能預知自己在某個坑種樹的獲利會是多少(可能為負),請你幫助他計算出他的最大獲利。

【輸入格式:】

第一行,兩個正整數n,k。

第二行,n個正整數,第i個數表示在直線上從左往右數第i個坑種樹的獲利。

【輸出格式:】

輸出1個數,表示cyrcyr種樹的最大獲利。

技術分享圖片
輸入樣例#16 3 
100 1 -1 100 1 -1
輸出樣例#1200
輸入輸出樣例

【算法分析:】

這時一道貪心的題目:

對於一個樹坑i,有兩種狀態:種樹或者不種樹

當選擇樹坑i種樹時,獲利為a[i]

而也可以選擇在(i - 1)和(i + 1)兩個位置種樹,所以將a[i]更新成a[i - 1] + a[i + 1] - a[i]

利用大根堆每次尋找最大值,並將更改後的值再次push進堆裏

如果選擇i後又選擇了(i - 1)和(i + 1),更新時 - a[i]的操作就顯得不可或缺了= =

利用堆優化後的算法復雜度為O(k log2 n)

【代碼:】

 1 //種樹
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<algorithm>
 5
#include<queue> 6 #include<vector> 7 8 #define pii pair<int, int> 9 #define mkp make_pair 10 #define fi first 11 #define se second 12 using namespace std; 13 14 const int MAXN = 500000 + 1; 15 16 priority_queue<pii> q; 17 18 int n, k; 19 int a[MAXN], l[MAXN], r[MAXN]; 20 bool
tree[MAXN]; 21 long long ans; 22 23 int main() { 24 scanf("%d%d", &n, &k); 25 for(int i = 1; i <= n; i++) { 26 scanf("%d", &a[i]); 27 q.push(mkp(a[i], i)); 28 l[i] = i - 1, r[i] = i + 1; 29 } 30 r[0] = 1, l[n + 1] = n; 31 while(k--) { 32 while(tree[q.top().se]) q.pop(); 33 pii tmp = q.top(); 34 q.pop(); 35 if(tmp.fi <= 0) break; 36 ans += tmp.fi; 37 int pos = tmp.se; 38 a[pos] = a[l[pos]] + a[r[pos]] - a[pos]; 39 tmp.fi = a[pos]; 40 tree[l[pos]] = tree[r[pos]] = 1; 41 l[pos] = l[l[pos]], r[l[pos]] = pos; 42 r[pos] = r[r[pos]], l[r[pos]] = pos; 43 q.push(tmp); 44 } 45 printf("%lld\n", ans); 46 }

【洛谷】【堆+貪心】P1484 種樹