题目描述
一位冷血的杀手潜入Na-wiat,并假装成平民。警察希望能在NN个人里面,查出谁是杀手。警察能够对每一个人进行查证,假如查证的对象是平民,他会告诉警察,他认识的人,谁是杀手,谁是平民。假如查证的对象是杀手,杀手将会把警察干掉。现在警察掌握了每一个人认识谁。每一个人都有可能是杀手,可看作他们是杀手的概率是相同的。
问:根据最优的情况,保证警察自身安全并知道谁是杀手的概率最大是多少?
Solution
首先缩点, 然后需要把缩完点后的DAG上每个入度为0的点都询问一次才行.
但是有一种特殊情况是有一个入度为0的点, 它连接的点都不是必须需要它.这时就可以不询问它了.
Code
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
const int N = 1e5 + 5, M = 3e5 + 6;
class BaseGraph {
public:
struct Edge {
int v; Edge* nxt;
Edge(int _, Edge* __) : v(_), nxt(__) { }
} *head[N];
int du[N];
BaseGraph() {
memset(du, false, sizeof du);
for (int i = 1; i < N; i += 1)
head[i] = nullptr;
}
void AddEdge(int u, int v) {
du[v] += 1; head[u] = new Edge(v, head[u]);
}
};
class Graph : public BaseGraph {
int dfn[N], low[N], vis[N], que[N], col[N], siz[N];
int vis_num, col_num, top;
void Tarjan(int u) {
dfn[u] = low[u] = ++vis_num;
vis[u] = true, que[++top] = u;
for (auto edge = head[u]; edge; edge = edge->nxt) {
if (not dfn[edge->v])
Tarjan(edge->v), low[u] = std:: min(low[u], low[edge->v]);
else if (vis[edge->v])
low[u] = std:: min(low[u], low[edge->v]);
}
if (dfn[u] == low[u]) {
vis[u] = false, col[u] = ++col_num, siz[col_num] = 1;
while (que[top] != u)
vis[que[top]] = false,
col[que[top--]] = col_num, siz[col_num] += 1;
top--;
}
}
public:
double init(int n, int m) {
for (int i = 0, u, v; i < m; i += 1) {
scanf("%d%d", &u, &v);
AddEdge(u, v);
}
for (int i = 1; i <= n; i += 1)
if (not dfn[i])
Tarjan(i);
BaseGraph* rG = new BaseGraph();
for (int u = 1; u <= n; u += 1)
for (auto edge = head[u]; edge; edge = edge->nxt)
if (col[u] != col[edge->v])
rG->AddEdge(col[u], col[edge->v]);
int num_without_du = 0;
for (int i = 1; i <= col_num; i += 1)
if (not rG->du[i])
num_without_du += 1;
for (int u = 1; u <= n; u += 1)
if (not rG->du[col[u]] and siz[col[u]] == 1) {
bool flag = false;
for (auto edge = head[u]; edge; edge = edge->nxt) {
if (rG->du[col[edge->v]] == 1) {
flag = true; break;
}
}
if (not flag) {
return 1.0 - 1.0 * (num_without_du - 1) / n;
}
}
return 1.0 - 1.0 * num_without_du / n;
}
};
int main () {
int n, m;
Graph* G = new Graph();
scanf("%d%d", &n, &m);
printf("%.6f\n", G->init(n, m));
return 0;
}
原文地址:https://www.cnblogs.com/qdscwyy/p/9835474.html
时间: 2024-10-19 16:29:40