復健計畫 2 貪心 經典的貪心題目 模型和思路

2021-10-08 18:40:57 字數 3948 閱讀 1971

復健題目:poj 2376,poj 1328,poj 3190,poj 2393,poj 1017和acwing上的貪心模板題目.

一、區間問題

區間問題一般可分為四類問題,簡稱為區間選點、區間分組、區間覆蓋和最大不相交區間數量

1、區間選點

題目的一般描述為:給定n個閉區間,請你在數軸上選擇盡量少的點,使得每個區間內至少包含乙個選出的點。輸出選擇的點的最小數量。位於區間端點上的點也算作區間內。

思路:1)先按區間右端點公升序排序;2)令比較初值st為-inf。列舉每個區間,若當前區間不包含點st則點數加一,並且st變為該區間右端點.

**:

#include

#include

#include

#include

using

namespace std;

const

int n=

100010

,inf=

0x3f3f3f3f

;int cnt,n;

struct node

;node a[n]

;bool

cmp(node a,node b)

intmain()

cout

}

2、區間分組

題目的一般描述:給定n個閉區間,請你將這些區間分成若干組,使得每組內部的區間兩兩之間(包括端點)沒有交集,並使得組數盡可能小。

思路:1)先按照區間右端點公升序排序;2)之後用堆(優先佇列)維護在每一組的最後乙個區間的右端點,令st=q.top();同時一次列舉區間,若不衝突則不增加組數,st=該區間右端點,q.push(st);若衝突,則增加組數,q.push(該區間右端點) .

經典例題poj 3190**:

因為此題輸出要求更高,需要存下原序號相關資訊,所以這裡的優先佇列在插入時不是乙個數字,而是乙個結構體,則需要過載運算子來滿足要求,此處這個操作我應當掌握.

#include

#include

#include

#include

#include

using

namespace std;

const

int n=

50010

;struct node

;node a[n]

;int n,ans[n]

,cnt;

//ans 原序號對應的

bool

cmp(node a,node b)

struct node_2

;bool

operator

<

(const node_2 &a,

const node_2 &b)

priority_queue q;

intmain()

sort

(a+1

,a+n+

1,cmp);

cnt++

; node_2 st;

st.num=a[1]

.num;

st.val=a[1]

.t; q.

push

(st)

; ans[a[1]

.num]

=cnt;

for(

int i=

2;i<=n;i++

)else

//cout<}

cout

int i=

1;i<=n;i++

)printf

("%d\n"

,ans[i]);

return0;

}

3、區間覆蓋

問題一般描述:給定n個閉區間以及乙個線段區間[s.t],請你選擇盡量少的區間,將指定線段區間完全覆蓋。輸出最少區間數,如果無法完全覆蓋則輸出-1。

思路:1)按區間左端點公升序排列;2)初值令st=第乙個區間的右端點(在s一定被覆蓋到的情況下),依次列舉區間,若當前區間的左端點<=st,則取st=min(st,當前區間的右端點);若所有區間都不滿足該條件,則輸出-1.

經典例題:poj 2376**:

此題要求和一般描述略有不同,因為該題的」區間「實際上是若干個離散的點,因此判斷時要注意細節.

#include

#include

#include

#include

using

namespace std;

const

int n=

25010

;struct node

; node a[n]

;int n,t;

int ans;

bool v[n]

;bool

cmp(node a,node b)

intmain()

sort

(a+1

,a+n+

1,cmp)

;memset

(v,0

,sizeof

(v))

;int st=1;

while

(st<=t)}if

((ans==n && st<=t)

|| flag)

} cout

}

類似題目poj 1328:

首先要對此題做轉化,將小島轉化成在x軸上的區間,然後對這些區間分組,使組數盡量小並且每組中任意兩個區間都存在交集.

#include

#include

#include

#include

#include

using

namespace std;

const

int n=

1010

;int n,d;

struct node

;node a[n]

;double sqrt (

double x)

;bool

cmp(node a,node b)

int ans,cnt;

intmain()

if(my>d)

sort

(a+1

,a+n+

1,cmp)

;double st=a[1]

.t; ans++

;for

(int i=

2;i<=n;i++

)else

}printf

("case %d: %d\n"

,cnt,ans);}

return0;

}

二、huffman樹、不等式類、湊硬幣類問題

1、huffman樹問題題目poj 3253和noip2023年的合併果子都是很經典的題目.

思路簡單說一下就是維護乙個小根堆,然後連續兩次取出堆頂元素合併,合併之後再放入堆中,直到堆中只剩乙個元素即可.

2、不等式類問題最典型的題目是利用絕對值不等式的倉庫選址和利用排序不等式的打水問題

即倉庫選址由三角不等式的縮放而選擇中位數,而打水問題則因為順序<=亂序<=逆序的原因從小到大排列所需時間.

3、湊硬幣類問題的一般描述:給定不同面值的硬幣各若干枚,然後要湊出乙個較大的面額,問怎樣湊用的硬幣數量最少.

稍微有所改變的例題如poj 1017

以上型別題目因為比較特殊,也無固定模板,就不貼**了.

4、貪心題目實際上沒有定式與模板,目前對我來說除了常見的題型,就只能憑感覺猜再找反例證明.

貪心經典題目

問題描述 有n個人排隊到r個水龍頭去打水,他們裝滿水桶的時間為t1,t2,tn為整數且各不相等,應如何安排他們的打水順序才能使他們花費的時間最少?樣例輸入 4 2 4人打水,2個水龍頭 2 6 4 5 每個打水時間 先放 include include include using namespace...

貪心經典小題

題目背景 快noip了,yyy很緊張!題目描述 現在各大oj上有n個比賽,每個比賽的開始 結束的時間點是知道的。yyy認為,參加越多的比賽,noip就能考的越好 假的 所以,他想知道他最多能參加幾個比賽。由於yyy是蒟蒻,如果要參加乙個比賽必須善始善終,而且不能同時參加2個及以上的比賽。輸入輸出格式...

貪心經典演算法 Kruskal演算法

kruskal演算法的高效實現需要一種稱作並查集的結構。我們在這裡不介紹並查集,只介紹kruskal演算法的基本思想和證明,實現留在以後討論。kruskal演算法的過程 1 將全部邊按照權值由小到大排序。2 按順序 邊權由小到大的順序 考慮每條邊,只要這條邊和我們已經選擇的邊不構成圈,就保留這條邊,...