ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[BZOJ2438]杀人游戏

2019-08-27 12:02:52  阅读:235  来源: 互联网

标签:游戏 int 杀手 top ++ maxN 杀人 include BZOJ2438


Description

一位冷血的杀手潜入 Na-wiat,并假装成平民。警察希望能在 N 个人里面,查出谁是杀手。警察能够对每一个人
进行查证,假如查证的对象是平民,他会告诉警察,他认识的人, 谁是杀手, 谁是平民。 假如查证的对象是杀
手, 杀手将会把警察干掉。现在警察掌握了每一个人认识谁。每一个人都有可能是杀手,可看作他们是杀手的概
率是相同的。问:根据最优的情况,保证警察自身安全并知道谁是杀手的概率最大是多少?

\(n\le 10^5, m\le 3\times 10^5\)

Solution

假设最优策略查了 \(x\) 个未知身份的人,那么概率就是 \(\frac{n - x}{n}\)

所以我们尽可能的查少的人。

首先,对于一个强连通分量,只要查一个人就可以把这个强连通分量全部安全查完。

所以先粗略考虑把每一个缩完点的一个个dag中入度为0的点查了,那么一定可以把杀手找出来。

然后就会被这个hack:

3 2
2 1
3 1

发现最优不是查2和3,而是仅查2或3。

于是仔细一想,发现若存在至少一个点满足它自己所在的强连通分量大小为1且它连出去的点的入度都 \(> 1\) ,那么这个点是不用查的,所以需要查的人数就会-1。

注意就算存在多个这样的点,查的人数也仅仅只会减少1,因为最后剩下的一定是这些点,而我们无法确定谁是杀手(否则查他们的话会付出更大的代价)。

Code

#include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <fstream>

typedef long long LL;
typedef unsigned long long uLL;

#define SZ(x) ((int)x.size())
#define ALL(x) (x).begin(), (x).end()
#define MP(x, y) std::make_pair(x, y)
#define DE(x) cerr << x << endl;
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define GO cerr << "GO" << endl;

using namespace std;

inline void proc_status()
{
    ifstream t("/proc/self/status");
    cerr << string(istreambuf_iterator<char>(t), istreambuf_iterator<char>()) << endl;
}
inline int read() 
{
    register int x = 0; register int f = 1; register char c;
    while (!isdigit(c = getchar())) if (c == '-') f = -1;
    while (x = (x << 1) + (x << 3) + (c xor 48), isdigit(c = getchar()));
    return x * f;
}
template<class T> inline void write(T x) 
{
    static char stk[30]; static int top = 0;
    if (x < 0) { x = -x, putchar('-'); }
    while (stk[++top] = x % 10 xor 48, x /= 10, x);
    while (putchar(stk[top--]), top);
}
template<typename T> inline bool chkmin(T &a, T b) { return a > b ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; }

const int maxN = 2e5 + 2;

int n, m;
int stk[maxN], top;
int low[maxN], dfn[maxN], dfst;
int in[maxN], size[maxN], cnt, col[maxN];
vector<int> g[maxN];

void link(int u, int v) { g[u].push_back(v); }

void tarjan(int u)
{
    int v;
    dfn[u] = low[u] = ++dfst;
    stk[++top] = u;
    for (int i = 0; i < SZ(g[u]); ++i)
    {
        v = g[u][i];
        if (!dfn[v])
            tarjan(v), chkmin(low[u], low[v]);
        else if (!col[v])
            chkmin(low[u], dfn[v]);
    }
    if (low[u] == dfn[u])
    {
        ++cnt;
        do
        {
            v = stk[top--];
            col[v] = cnt;
            size[cnt]++;
        } while (u != v);
    }
}

bool chk(int u)
{
    if (size[col[u]] != 1) return 0;
    if (in[col[u]]) return 0;
    for (int i = 0; i < SZ(g[u]); ++i)
    {
        int v = g[u][i];
        if (in[col[v]] <= 1)
            return 0;
    }
    return 1;
}

int main() 
{
#ifndef ONLINE_JUDGE
    freopen("xhc.in", "r", stdin);
    freopen("xhc.out", "w", stdout);
#endif
    n = read(), m = read();
    for (int i = 1; i <= m; ++i) { int u = read(), v = read(); link(u, v); }
    for (int i = 1; i <= n; ++i) if (!dfn[i]) tarjan(i);
    for (int i = 1; i <= n; ++i)
        for (int j = 0; j < SZ(g[i]); ++j)
            if (col[g[i][j]] != col[i])
                in[col[g[i][j]]]++;
    int ans = 0, delta = 0;
    for (int i = 1; i <= cnt; ++i) if (!in[i]) ans++;
    for (int i = 1; i <= n; ++i) if (chk(i)) delta++;
    if (delta) printf("%.6lf\n", (double)(n - ans + 1) / n);
    else printf("%.6lf\n", (double) (n - ans) / n);
    return 0;
}

标签:游戏,int,杀手,top,++,maxN,杀人,include,BZOJ2438
来源: https://www.cnblogs.com/cnyali-Tea/p/11417538.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有