【BZOJ-2438】杀人游戏 Tarjan + 缩点 + 概率

2438: [中山市选2011]杀人游戏

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit:
1638  Solved: 433
[Submit][Status][Discuss]

Description

一位冷血的杀手潜入 Na-wiat,并假装成平民。警察希望能在 N 个人里面,查出谁是杀手。

警察能够对每一个人进行查证,假如查证的对象是平民,他会告诉警察,他认识的人, 谁是杀手, 谁是平民。 假如查证的对象是杀手,
杀手将会把警察干掉。
现在警察掌握了每一个人认识谁。
每一个人都有可能是杀手,可看作他们是杀手的概率是相同的。

问:根据最优的情况,保证警察自身安全并知道谁是杀手的概率最大是多少?

Input

第一行有两个整数 N,M。
接下来有 M 行,每行两个整数 x,y,表示 x 认识 y(y 不一定认识 x,例如 胡 锦 涛 同志)

Output

仅包含一行一个实数,保留小数点后面 6 位,表示最大概率。

Sample Input

5 4
1 2
1 3
1 4
1 5

Sample Output

0.800000

HINT

警察只需要查证 1。假如1是杀手,警察就会被杀。假如 1不是杀手,他会告诉警
察 2,3,4,5 谁是杀手。而 1 是杀手的概率是
0.2,所以能知道谁是杀手但没被杀的概
率是0.8。对于 100%的数据有 1≤N ≤  10 0000,0≤M ≤  30
0000

数据已加强!

Source

Solution

不错的题,思路应该比较简单,但容易遗漏问题

把认识关系转化到图上,那么我们发现,如果我们询问一个平民,那么他的所有后继点就都知道了

那么我们先对图进行Tarjan缩一下点,有入度的点,显然我们可以不用直接访问,那么我们访问每个入度为0的点

不过这里有个特殊情况,如果存在一个被搁置的点,他最后是不用访问的比如:3个人ABC,A认识B,那么访问A后,A,B和C的身份都能得知

这样就可以少询问一个,但是注意,这种情况的条件是:

入度为0,且只包含1个点,且这个点指向的SCC的入度>=2(缩点前)【并不仅仅是出入度为0】<-特别容易出错

比如:3个人ABC,A认识B,C认识B,那么访问A或C后都可以得到所有人身份;

证明:

若这个点的所有出边所指向的强连通分量都有其它的前驱 那么我把这个点放在最后 用作排除不会对推理造成干扰 反之若有一个后继入度为1 那么就算不调查这个单点也要调查那个后继 对答案没有影响

然后答案显然是(N-x)/N (x为需要询问的点数)

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
using namespace std;
int read()
{
    int x=0,f=1; char ch=getchar();
    while (ch<‘0‘ || ch>‘9‘) {if (ch==‘-‘) f=-1; ch=getchar();}
    while (ch>=‘0‘ && ch<=‘9‘) {x=x*10+ch-‘0‘; ch=getchar();}
    return x*f;
}
#define MAXN 100010
#define MAXM 300010
int N,M;
struct EdgeNode{int next,to;}edge[MAXM],road[MAXM];
int cnt,tot,head[MAXN],last[MAXN];
void AddEdge(int u,int v) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v;}
void AddRoad(int u,int v) {tot++; road[tot].next=last[u]; last[u]=tot; road[tot].to=v;}
int dfn[MAXN],low[MAXN],scc,t,belong[MAXN],visit[MAXN],size[MAXN],ind[MAXN],ans,st[MAXN],top;
void Tarjan(int x)
{
    dfn[x]=low[x]=++t;
    visit[x]=1; st[++top]=x;
    for (int i=head[x]; i; i=edge[i].next)
        if (!dfn[edge[i].to])
            Tarjan(edge[i].to),low[x]=min(low[x],low[edge[i].to]);
        else
            if (visit[edge[i].to]) low[x]=min(low[x],dfn[edge[i].to]);
    if (dfn[x]==low[x])
        {
            scc++; int now=0;
            while (x!=now)
                now=st[top--],size[scc]++,
                visit[now]=0,belong[now]=scc;
        }
}
map<int,bool>mp;
bool check(int x)
{
    if (ind[x]!=0 || size[x]!=1) return 0;
    for (int i=last[x]; i; i=road[i].next)
        if (ind[road[i].to]==1) return 0;
    return 1;
}
int main()
{
    N=read(),M=read();
    int x,y;
    while (M--) x=read(),y=read(),AddEdge(x,y);
    for (int i=1; i<=N; i++) if (!dfn[i]) Tarjan(i);
    for (int i=1; i<=N; i++)
        {
            mp.clear();
            for (int j=head[i]; j; j=edge[j].next)
                if (belong[i]!=belong[edge[j].to] && !mp[belong[edge[j].to]])
                    ind[belong[edge[j].to]]++,AddRoad(belong[i],belong[edge[j].to]),mp[belong[edge[j].to]]=1;
        }
    for (int i=1; i<=scc; i++) if (!ind[i]) ans++;
    for (int i=1; i<=scc; i++)
        if (check(i)) {ans--;break;}
    printf("%.6lf",double(N-ans)/N);
    return 0;
}

这题一眼秒思路,然后细节WA了好久...最后看了Po姐才了解到问题

细节啊细节!!

时间: 2024-10-19 00:10:41

【BZOJ-2438】杀人游戏 Tarjan + 缩点 + 概率的相关文章

BZOJ 2438 杀人游戏(强连通分量)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2438 题意:一位冷血的杀手潜入某村庄,并假装成 平民.警察希望能在 N 个人里面,查出谁是杀手. 警察能够对每一个人进行查证,假如查证的对象是平民,他会告诉警察,他认识的人, 谁是杀手, 谁是平民. 假如查证的对象是杀手, 杀手将会把警察干掉. 现在警察掌握了每一个人认识谁. 每一个人都有可能是杀手,可看作他们是杀手的概率是相同的. 问:根据最优的情况,保证警察自身 安全并知道谁是杀手

[中山市选]杀人游戏 Tarjan+概率

[中山市选]杀人游戏 Tarjan+概率 题目描述 ? 一位冷血的杀手潜入\(Na\)-\(wiat\),并假装成平民.警察希望能在\(N\)个人里面,查出谁是杀手.警察能够对每一个人进行查证,假如查证的对象是平民,他会告诉警察,他认识的人,谁是杀手,谁是平民.假如查证的对象是杀手,杀手将会把警察干掉.现在警察掌握了每一个人认识谁.每一个人都有可能是杀手,可看作他们是杀手的概率是相同的. 问:根据最优的情况,保证警察自身安全并知道谁是杀手的概率最大是多少? 输入输出格式 输入格式: ? 第一行有

[BZOJ 1179]ATM题解 Tarjan缩点+SPFA

[BZOJ 1179]ATM题解 Tarjan缩点+SPFA Description Input 第一行包含两个整数N.M.N表示路口的个数,M表示道路条数.接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号.接下来N行,每行一个整数,按顺序表示每个路口处的ATM机中的钱数.接下来一行包含两个整数S.P,S表示市中心的编号,也就是出发的路口.P表示酒吧数目.接下来的一行中有P个整数,表示P个有酒吧的路口的编号 Output 输出一个整数,

BZOJ 2438 中山市选2011 杀人游戏 Tarjan

题目大意:有n个人,其中一个是杀手,可以询问一些人,如果是杀手就会死,如果是平民,他会告诉你他认识的人中有谁是杀手有谁是平民 警告:数据有误,请谨慎提交! 易知如果我需要访问x个人,那么答案就是1-x/n 我们需要访问最少的人 如果我访问的人是平民,那么这个点所有的后继我都能知道 于是Tarjan缩点之后入度为零的点就是答案 但是还有一个问题 比如说这组样例 3 1 1 2 我访问了1,那么1和2是不是凶手我就都知道了 既然只有三个人,我知道1和2是不是凶手,那么3也一定知道 没必要去访问3 于

【BZOJ2438】[中山市选2011]杀人游戏 Tarjan

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

bzoj2438 杀人游戏 Tarjan强联通

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

BZOJ 2438 中山市选 2011 杀人游戏 Tarjan

题目大意:给出一张有向人物关系图,告诉你谁认识谁,认识具有传递性.其中有一个人是犯人.现在警察要调查谁是犯人.他可以问任何人.但是如果他问到了犯人,那么它就会死.如果他问到的一个人认识犯人,这个人就会告诉警察谁是犯人.问警察保证自身安全并知道犯人是谁的概率最大是多少. 思路:这个题前一阵子重测了,加强了数据,卡掉了网上一片AC代码.. 正解并不是很难想.首先先缩点,整个图变成拓扑图,之后会出现一些类似根的东西,这些scc入度为0,只要警察询问了这些scc每一个中的任意一个,就肯定能知道谁是犯人.

[BZOJ2438]杀人游戏(缩点+特判)

题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=2438 分析:如果出现了环,那么只要询问环上的一个人,那么环上其他的人的信息也就知道了,所以相当于一个点,于是先缩点成一个DAG图. 对于这个DAG图,我们可以知道最优的情况就是询问那些入度为0的点,那么接下来的点就能全部确定了,但是每询问一个点,失败的概率就会增加1/n,所以ans=1-入度为0的点的个数*(1/n) 但是有特殊的情况,如果有个点它缩点前是一个点并且它的出边指向的边的

[BZOJ 1051][HAOI 2006]受欢迎的牛(tarjan缩点)

http://www.lydsy.com:808/JudgeOnline/problem.php?id=1051 唔...这题好像在POJ上见过? 比较水的题,很好想出思路.牛和牛之间的关系就像有向图,牛a喜欢牛b相当于建立有向边a->b,然后在这个有向图中,每个强连通分量里的牛们相当于是相互喜欢的,把这个图缩点成DAG,DAG里如果有且仅有一个出度为0的点,则这个点对应强连通分量里的所有牛都是受欢迎的牛,如果没有出度为0的点,当然就没受欢迎的牛了,如果出度为0的点的个数大于1,则每个出度为0的