bzoj 2438: [中山市选2011]杀人游戏 (强联通分量 Tarjan)

Description

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

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

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

Input

第一行有两个整数 N,M。

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

Output

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

题解

一开始看到这个题还以为是关于概率和期望的问题,,结果发现这题的概率就是个没有技术含量的东西,,假如警察一共只询问了x个人的话,那么安全的概率就是1-x/n,,所以说关键就是求出x的值;

我们发现如果将所有关系看作一棵树的话,那么我们只要调查树的根节点就可以了,也就是说我们的答案就是1-根节点数/节点总数;但是我们发现这个有向图并不是一棵树,而是有环存在的,这样我们就无法将图转换成一棵树,,这时我们可以考虑缩点,,因为如果关系构成环的话,那么我们调查环内的任何一个节点都可以将整个环调查出来,也就是说对于整个环,我们只需算作一次调查,所以我们可以将环用Tarjan算法缩成一个点,这样整个图就变成了一个有向无环图,即一棵树,然后我们将图遍历一遍,求出入度为1的节点(即根节点)个数,然后算出答案即可。

还需要注意一个问题,由于题目的关系,我们可以知道如果最后只剩一个点没有调查,那么可以直接确定这个点的身份,就不用再次调查一遍了。那么这个单点应该怎么确定呢?首先它的入度要为0,其次它的出边所连的点应该可以包含在其他子树中(也就是相连点的入度大于1),那么这个点就可以放到最后,先询问其他点,这样最后这个点的身份也就确定了。所以如果我们发现有这样的点的话,令根节点数减1就可以了。

代码如下

#include<algorithm>
#include<iostream>
#include<cstring>
#include<climits>
#include<cstdio>
#define INF INT_MAX/2
#define N 100010
#define M 300010
using namespace std;
struct Edge { int to,next;Edge() { next=to=0; } }edge[M];
double ans=1;int v[N],b[N],in[N];     //v[]表示该点是否访问过,b[]表示该点是否在栈中
int n,m,dl[N],top,low[N],dfn[N],t,to[N],head[N],tot;
int input() {
    char c=0;int s=0;
    while(c<‘0‘||c>‘9‘) c=getchar();
    while(c>=‘0‘&&c<=‘9‘) s=s*10+c-‘0‘,c=getchar();
    return s;
}
void Add_edge(int a,int b) {
    Edge &e=edge[tot];e.to=b,e.next=head[a];head[a]=tot++;
}
void reduce(int p) {
    while(top>=p) {
      b[dl[top]]=false;
      to[dl[top--]]=dl[p];           //to[]为该元素所属的强联通分量
    } return;
}
int dfs(int now) {
    if(b[now]) return low[now]; if(v[now]) return INF;
    v[now]=b[now]=true;low[now]=dfn[now]=++t;
    int o;dl[o=++top]=now;
    for(int i=head[now];i!=-1;i=edge[i].next) {
      low[now]=min(low[now],dfs(edge[i].to));
    }
    if(low[now]==dfn[now]) reduce(o); return low[now];
}
void Tarjan() {
    for(int i=1;i<=n;i++) if(v[i]==false) dfs(i);
}
void work() {
    memset(v,0,sizeof(v));                  //v[]在此函数中为强联通分量的元素个数
    bool c=false;for(int i=1;i<=n;i++) {
      for(int j=head[i];j!=-1;j=edge[j].next)
          if(to[i]!=to[edge[j].to])
            in[to[edge[j].to]]++;           //统计强连通分量入度
      if(to[i]!=i) v[to[i]]++;              //统计该强连通分量的元素个数
    }
    int s=0;for(int i=1;i<=n;i++) {         //s为根节点的个数
      if(to[i]==i&&!in[i]) {
        s++; if(c==false&&!v[i]) {
          int j=-1;
          for(j=head[i];j!=-1;j=edge[j].next) {
            if(in[edge[j].to]==1) { break; }
          }
          if(j==-1) c=true;
        }
      }
    }
    if(c==true) ans-=(s-1)/(double)n;
    else ans-=s/(double)n;
}
int main() {
    n=input();m=input();int a,b;memset(head,-1,sizeof(head));
    for(int i=1;i<=m;i++) { a=input(),b=input();Add_edge(a,b); }
    Tarjan(); work(); printf("%.6lf",ans); return 0;
}
时间: 2024-09-30 22:21:52

bzoj 2438: [中山市选2011]杀人游戏 (强联通分量 Tarjan)的相关文章

bzoj2438: [中山市选2011]杀人游戏(强联通+特判)

2438: [中山市选2011]杀人游戏 题目:传送门 简要题意: 给出n个点,m条有向边,进行最少的访问并且可以便利(n-1)个点,求这个方案成功的概率 题解: 一道非常好的题目! 题目要知道最大的存活概率,那么也就是找到直接找到杀手的最小概率 那么我们采用强联通缩点: 统计每个联通分量的入度,如果入度为0(证明除此联通分量里的点,没有人可以知道连通分量里的信息,那就一定要先选一个人访问),那么sum++(因为依据题意,假如问到连通分量里的任意一个人,只要ta不是杀手,那么一定可以安全的遍历强

bzoj 2438 [中山市选2011]杀人游戏(SCC+概率)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2438 [题意] N个人中有一个杀手,每次询问一个人可能被杀或被告知其认识的人中谁是杀手谁是平民,问不被杀的情况下知道谁是杀手的概率. [思路] 对于一个scc,如果我们询问一个不是杀手的人,就可以成功遍历整个scc. 求scc,然后缩点. 对于每一个入度为0的scc,我们需要去询问一下,那么被杀的概率为1/n * ans.ans为入度为0的scc个数. 但还有一种特殊的情况,如果一个

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

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

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

Description 给你一个有向图,求至少询问多少次能够得到全部点的信息. Sol Tarjan + 强连通分量缩点 + 判断. 先缩点,如果我们知道了强连通分量里的任意一个点,我们就可以知道这些点的信息,和这些点所连接的其他点的信息,显然我们需要知道的就是缩点后入度为0的点. 然后还有最后一个入度为0的单点,并且他的所有儿子都能被其他节点访问,那么最后就可以直接推断出这个点,所以要删去. Code #include<cstdio> #include<stack> #inclu

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

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

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

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

2438. [中山市选2011]杀人游戏【强连通分量】

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

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

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

[中山市选2011]杀人游戏

[中山市选2011]杀人游戏 时间限制: 1 Sec  内存限制: 128 MB提交: 64  解决: 33[提交][状态][讨论版] 题目描述 一位冷血的杀手潜入 Na-wiat,并假装成平民.警察希望能在 N 个人里面,查出谁是杀手. 警察能够对每一个人进行查证,假如查证的对象是平民,他会告诉警察,他认识的人, 谁是杀手, 谁是平民. 假如查证的对象是杀手, 杀手将会把警察干掉. 现在警察掌握了每一个人认识谁. 每一个人都有可能是杀手,可看作他们是杀手的概率是相同的. 问:根据最优的情况,保