拓撲排序 貪心 小C與桌遊(洛谷 P5603)

2021-10-23 07:02:09 字數 1713 閱讀 9712

題目描述

這個桌遊的地圖可以被抽象成乙個 n 個點,m 條邊的有向無環圖(不保證連通),小c在這個地圖上行走,小c能走到某個點當且僅當能夠到達這個點的所有點都已經被小c走到。小c會走到每個點恰好 1 次,並且他能走到哪些點與他當前所在的點沒有關係(即可以走到與當前所在的點沒有連邊的點,只要滿足之前的條件)。

小c每走到乙個標號比之前走到的點都大的點,他就會有 1/2 的概率從對手那裡拿到 1 籌碼,有 1/2 的概率給對手 1 塊籌碼,雙方初始各有 1919810 個籌碼。

小c的運氣時好時壞,所以他希望你幫他計算出:

在最優情況下,即他每次都能從對手那裡拿到籌碼時,他採取最優的行走方式能得到的籌碼數。

在最劣情況下,即對手每次都能從他那裡拿到籌碼時,他採取最優的行走方式會失去的籌碼數。

題目很容易看出來是拓撲排序,第一問也比較好像,直接

priority_queue< int,vector< int >,greater< int> >qu,維護最小的元素;

第二問就比較難了,如果直接跟第一問反過來,維護最大元素,肯定是有問題的,如圖:

發現這個圖如果貪心每次出最大點,那麼拓撲序列是 2、3、1、4 ,這個答案是3

可以把拓撲序列改為 2、1、4、3,那麼答案為2;

所以可以總結為:當入隊元素大於mmax時,把這個元素入到priority_queue佇列裡面,維護最大值,如果不大於mmax,就入到queue佇列裡面,繼續bfs;

**:

#include

#define ll long long

#define pa pair

#define ls k<<1

#define rs k<<1|1

#define inf 0x3f3f3f3f

using

namespace std;

const

int n=

500100

;const

int m=

100000

;const ll mod=

1e9+7;

inline

intread()

while

(c>=

'0'&&c<=

'9')

return x*sign;

}int n,m,cnt,head[n]

,in1[n]

,in2[n]

;int ans1,ans2;

vector<

int>ve1;

struct nodeedge[n*2]

;void

add(

int p,

int q)

void

bfs1()

}}void

bfs2()

while

(!qu2.

empty()

)}}}

}int

main()

bfs1()

;bfs2()

;int mmax=0;

for(

int i=

0;isize()

;i++)}

cout<

cout<

return0;

}

Luogu P5603 小C與桌遊

這個題一看和入度扯上關係就是明顯的topo了。對於最優情況,直接維護小根堆,貪心即可。對於最劣情況,顯然直接維護大根堆然後貪心是錯誤的 反例見luogu題解 所以每次要取出所有能拓展的節點,依次加入佇列topo即可。這裡注意當連到的點比當前最大值大時,壓入大根堆,否則加入佇列。code includ...

洛谷P5603 小C與桌遊

題目鏈結 小c是乙個熱愛桌遊的高中生,現在他被乙個桌遊難住了,快來幫幫他!這個桌遊的地圖可以被抽象成乙個 n 個點,m 條邊的有向無環圖 不保證連通 小c在這個地圖上行走,小c能走到某個點當且僅當能夠到達這個點的所有點都已經被小c走到。小c會走到每個點恰好 1 次,並且他能走到哪些點與他當前所在的點...

洛谷10月月賽 III 小C與桌遊

該問題可以分為兩個子問題 1.求一種拓撲順序使點的編號最大值的更新次數最多。2.求一種拓撲順序使點的編號最大值的更新次數最少。對於第乙個子問題,我們貪心的想,每次走到所有能走的點中編號最小的點。這種貪心顯然是正確的,因為如果我們先走編號較大的點,再走編號較小的點,顯然不如先走編號較小的點更優一些。所...