P4819 中山市選 Tarjan SCC

2021-10-22 17:35:17 字數 2162 閱讀 7634

題意

傳送門 p4819 [中山市選]殺人遊戲

題解若 x

xx 認識 y

yy,則從 x

xx 向 y

yy 連一條有向邊,得到一張有向圖。觀察發現,若存在環,那麼任取環上一點即可,則有 1/n

1/n1/

n 的概率是殺手;否則,可獲取下乙個節點的身份,直到環上最後乙個節點或發現殺手。

那麼使用 tar

ja

ntarjan

tarjan

演算法求解 scc

sccsc

c,縮減建圖,得到乙個 dag

dagda

g。對於入度為 0

00 的點 x

xx,顯然無法通過檢查其他節點來獲取 x

xx 的身份,那麼需要檢查這個節點。對於入度大於 0

00 的節點 x

xx,可以通過拓撲序小於它的節點 y

yy 來獲取 x

xx 的身份。那麼需要檢查的節點為 sum

=∑x∈

g[in

deg[

x]=0

]sum=\sum\limits_ \big[indeg[x]=0\big]

sum=x∈

g∑​[

inde

g[x]

=0]。

但演算法仍不完全正確,因為獲取某個人的身份,除了檢查、從認識其的人了解,還有第三種方法:排除法。若圖中僅剩最後乙個節點未了解其身份,那麼必然可以通過排除法進行推斷。那麼需要判斷入度為 0

00 的點中,是否存在可以運用排除法的節點。

首先,這樣的節點對應的 scc

sccsc

c 中節點個數為 1

11,否則不能判斷環上的其他節點的身份;其次,這樣的節點 x

xx 若存在出邊 (x,

y)

(x,y)

(x,y

),則 y

yy 一定有一條來自其他節點 z

zz 的入邊,否則 y

yy 的身份無法了解,為了簡單的判斷是否存在這樣的入邊,在建立 dag

dagda

g 時將節點間連邊去重,即可用節點的入度表示節點可以被多少個不同的節點更新。

#include

using

namespace std;

const

int maxn =

100005

, maxm =

300005

;int n, m, num, low[maxn]

, dfn[maxn]

;int tot, head[maxn]

, to[maxm]

, nxt[maxm]

;int tot_c, hc[maxn]

, tc[maxm]

, nc[maxm]

;int top, st[maxn]

, scc, sc[maxn]

, in[maxn]

, sz[maxn]

;bool ins[maxn]

, vs[maxn]

;inline

void

add(

int x,

int y)

inline

void

add_c

(int x,

int y)

void

tarjan

(int x)

if(low[x]

== dfn[x]

)while

(y != x);}

}int

main()

for(

int j = head[i]

; j; j = nxt[j]

) vs[sc[to[j]]]

=0;}

int sum =

0, lst =0;

for(

int i =

1; i <= scc;

++i)if(

!in[i])}

printf

("%.6f\n",(

double

)(n - sum)

/ n)

;return0;

}

P4819 中山市選 殺人遊戲

這題想必大家很容易想到圖論建模。每個人都是乙個結點,與他認識的人連一條邊,每過乙個點我們就能這樣擴充套件下去。我們需要使 殺的概率小,簡單貪心 盡量去找認識人多的人詢問,即找到聯通較多邊的那個結點詢問。我們可以求出途中所有的強連通分量,用tarjan演算法縮點,然後找出所有入讀為0的點。但這題有乙個...

P4819 中山市選 殺人遊戲

一位冷血的殺手潛入na wiat,並假裝成平民。警察希望能在nn個人裡面,查出誰是殺手。警察能夠對每乙個人進行查證,假如查證的物件是平民,他會告訴警察,他認識的人,誰是殺手,誰是平民。假如查證的物件是殺手,殺手將會把警察乾掉。現在警察掌握了每乙個人認識誰。每乙個人都有可能是殺手,可看作他們是殺手的概...

洛谷 P4819 中山市選 殺人遊戲 強連通分量

題目描述 一位冷血的殺手潛入na wiat,並假裝成平民。警察希望能在 n n 個人裡面,查出誰是殺手。警察能夠對每乙個人進行查證,假如查證的物件是平民,他會告訴警察,他認識的人,誰是殺手,誰是平民。假如查證的物件是殺手,殺手將會把警察乾掉。現在警察掌握了每乙個人認識誰。每乙個人都有可能是殺手,可看...