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