題意
傳送門 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 個人裡面,查出誰是殺手。警察能夠對每乙個人進行查證,假如查證的物件是平民,他會告訴警察,他認識的人,誰是殺手,誰是平民。假如查證的物件是殺手,殺手將會把警察乾掉。現在警察掌握了每乙個人認識誰。每乙個人都有可能是殺手,可看...