堆一般有兩個重要的操作,put(往堆中加入乙個元素)和get(從堆中取出並刪除乙個元素)。put一般用來建堆和維護堆,get則是得到最小值。
堆在noip競賽中應用廣泛,常用與快速查詢最大(最小值),優化各種演算法(如:最短路演算法、dp演算法),是一種效率高,應用廣泛的資料結構。
顯然,堆只能以乙個關鍵字作為順序,若乙個決策涉及時間和權值,那就必須轉換問題,使時間(或權值)的條件弱化,這樣就可以愉快地貪心了
下面以大根堆為例:
void
up(node x)
}
void
down()
}
題目描述
如題,初始小根堆為空,我們需要支援以下3種操作:
操作1: 1 x 表示將x插入到堆中
操作2: 2 輸出該小根堆內的最小數
操作3: 3 刪除該小根堆內的最小數
解析:板子題
#include
#include
#include
using
namespace std;
const
int maxn=
100005
;int n,a[maxn]
,heap[maxn]
,cnt=0;
voidup(
int p)
}void
down
(int p)
}int
main()
else
if(ok==2)
printf
("%d\n"
,heap[1]
);else
}}
解析:我們可以發現,假設能釣到魚的數量僅和已釣魚的次數有關,且每次釣魚的時間都是整數分鐘。則每次釣魚都要取當前最大值。但本題路程是變數,可以列舉到達的最遠魚塘,顯然不會走回頭路(因為與釣魚先後無關),我們可以加入[1,i]的魚塘,令t=m
−l[i
]t=m-l[i]
t=m−l[
i],其中l
ll表示路程所花費時間。每次從二叉堆中取出並刪除最大值,修改後再加入,重複t
tt次就得到了當前最大價值。
#include
#include
#include
using
namespace std;
const
int maxn=
105;
struct nodeheap[maxn]
,st,now;
int n,m,cnt,a[maxn]
,b[maxn]
,l[maxn]
,ans;
void
up(node x)
}node down()
return res;
}int
main()
scanf
("%d"
,&m)
;for
(int i=
1;i<=n;i++
)while
(t--
) ans=
max(ans,tot);}
printf
("%d"
,ans)
;}
二叉堆其實很擅長於求前m個大的決策,我們通常是先求最大,再求次大,以此推廣。或者先求區域性最優解,再縮小問題規模,直到問題解決。(貪心思想)
顯然可以有70pts的dp**:
#include
#include
#include
#define ll long long
using
namespace std;
const
int maxn =
100005
;ll n, k, a[maxn]
, f[maxn]
, dp[3]
[maxn]
;int
main()
for(
int i =
0; i <=
2; i++
) dp[i][0
]=0;
for(
int i =
2; i <= n; i++)}
printf
("%lld"
, dp[n %3]
[k])
;}
不難想到, 為了使佈線長度盡量小,每對佈線的辦公樓一定是相鄰的
所以我們可以在讀入時計算差分陣列儲存每相鄰兩個辦公樓的距離
這樣問題轉化為, 在差分陣列中找k個數,滿足k個數之和最小且互不相鄰
設差分陣列為b, 其中最小的數為b[i]
顯然最優解必定是一下其中一種
1.包含b[i]以及除b[i-1]和b[i+1]的數
2.包含b[i-1]和b[i+1]以及除b[i],b[i-2],b[i+2]
從這一點擴充套件, 可以先取b[i],並以b[i-1]+b[i+1]-b[i]替換,
然後在新數列中繼續重複k-1次得到最後結果
這樣若b[i]不屬於最優解,則b[i-1]+b[i+1]-b[i]必定被選,滿足了上述第二種情況
更具體做法是, 將原差分陣列每個值插入堆, 並將陣列以煉表串起來
每次取堆頂最小值更新答案,並刪除該值,
設最小值編號為i, 那麼再插入b[ pre[i] ]+b[ nxt[i] ]-b[i], 並更新鍊錶
重複k次即得最優解
#include
using
namespace std;
const
int maxn=
100005
;const
int inf=
0x3f3f3f3f
;void
read
(long
long
&x)while
(c>=
'0'&&c<=
'9')
x*=f;
}long
long n,k,m,ans,l[maxn]
,r[maxn]
,p[maxn]
;bool vis[maxn]
;priority_queuelong
long
,int
>
> q;
intmain()
for(
int i=
1;i<=m;i++
) p[0]
=p[n]
=inf;
//為什麼要這樣賦值?
for(
int i=
1;i<=k;i++
)printf
("%lld"
,ans)
;}
二叉堆學習總結
二叉堆是一種特殊的堆,二叉堆是完全二元樹 二叉樹 或者是近似完全二元樹 二叉樹 二叉堆有兩種 最大堆和最小堆。最大堆 父結點的鍵值總是 大於或等於 任何乙個子節點的鍵值。最小堆 父結點的鍵值總是 小於或等於 任何乙個子節點的鍵值。二叉堆用陣列儲存,從下標1開始,並且因為二叉堆為完全二叉樹,所以除根節...
(二叉)堆操作
堆操作 實驗目的 一 建堆 將陣列a 1.n 變成乙個最大堆。二 堆排序 將乙個堆中的元素按遞減排序輸出。三 用插入方法建堆 堆大小從1到n每次插入乙個元素到堆中,直到n個元素入堆。實驗原理 二叉 堆是乙個陣列,它可以被看成乙個近似的完全二叉樹。樹上的每乙個結點對應陣列中的乙個元素。除了最底層外,該...
簡單 二叉堆
堆是一種比較有用的資料結構,是二叉樹的一種陣列的表示形式。最大堆和最小堆是二叉堆的兩種形式。最大堆 根結點的鍵值是所有堆結點鍵值中最大者。最小堆 根結點的鍵值是所有堆結點鍵值中最小者。而最大 最小堆集結了最大堆和最小堆的優點,這也是其名字的由來。最大 最小堆是最大層和最小層交替出現的二叉樹,即最大層...