洛谷P4819 殺人遊戲

2022-06-13 22:36:12 字數 1484 閱讀 3401

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

問:根據最優的情況,保證警察自身安全並知道誰是殺手的概率最大是多少。

考慮到在乙個強連通分量裡,問任意乙個人情況,只要這個人不是殺手,那麼就可以把這個強連通分量裡所有人的身份得知。所以果斷縮點。

那麼就得到了一張 dag。我們只需要將這張 dag 中所有入度為 0 的點(也就是原先的乙個強連通分量)詢問即可得出所有人的身份。設入度為 0 的點有 \(k\) 個,那麼只需要問 \(k\) 次即可。

但是考慮一種情況:已經得知其中 \(n-1\) 個人均為平民,那麼排除法即可知道最後乙個人是殺手。所以如果存在乙個大小為 1 且沒有入度的強連通分量,那麼只需要問 \(k-1\) 次即可。

那麼答案就是 \(1-\frac\)。特殊情況 \(k\) 要減一。

時間複雜度 \(o(n)\)。

#include #include #include #include #include using namespace std;

const int n=300010;

int head[n],dfn[n],low[n],deg[n],pos[n],u[n],v[n];

int n,m,tot,cnt,ans;

bool vis[n];

vectorscc[n];

stackst;

struct edge

e[n];

void add(int from,int to)

void tarjan(int x)

else if (vis[v])

low[x]=min(low[x],low[v]);

} if (low[x]==dfn[x])

while (y!=x); }}

int check()

if (flag) return 1;

} return 0;

}int main()

tot=0;

for (int i=1;i<=n;i++)

if (!dfn[i]) tarjan(i);

for (int i=1;i<=m;i++)

if (pos[u[i]]!=pos[v[i]]) deg[pos[v[i]]]++;

for (int i=1;i<=cnt;i++)

if (!deg[i]) ans++;

memset(deg,0,sizeof(deg));

for (int i=1;i<=m;i++)

deg[v[i]]++;

printf("%0.6lf",1.0-1.0*(ans-check())/n);

return 0;

}

P4819 中山市選 殺人遊戲

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

P4819 中山市選 殺人遊戲

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

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

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