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

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

题目:传送门

简要题意:

   给出n个点,m条有向边,进行最少的访问并且可以便利(n-1)个点,求这个方案成功的概率

题解:
   一道非常好的题目!

   题目要知道最大的存活概率,那么也就是找到直接找到杀手的最小概率

   那么我们采用强联通缩点:

   统计每个联通分量的入度,如果入度为0(证明除此联通分量里的点,没有人可以知道连通分量里的信息,那就一定要先选一个人访问),那么sum++(因为依据题意,假如问到连通分量里的任意一个人,只要ta不是杀手,那么一定可以安全的遍历强联通分量里的所有人)

   接下来就是最关键的特判:

   对于连通分量里只有一个点的情况,如果它的入度为零,不一定就要访问(这里何前面似乎有些许矛盾)

   解释:如果有联通分量只有一个家族成员,并且没有入度,因为杀手只有一个,那么我们完全可以在遍历其他的n-1个点时得出答案(排除法嘛)

   但是它的出度不一定为0,所以还要判断一下在上面的基础上,这个点连出去的边是否能够被其他点访问(入度>1),很好理解吧

   如果以上的都满足,那么sum--

   还有一个小槽点:sum--一次就好了,因为如果有两种相同的情况,那么对于两个独立的点,我们还是要选择一个访问才能遍历完成的

   输出1.0-double(sum)/double(n)

代码:

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<cstdlib>
  4 #include<cmath>
  5 #include<algorithm>
  6 using namespace std;
  7 int n,m;
  8 struct node
  9 {
 10     int x,y,next;
 11 }a[1110000];int len,last[510000];
 12 void ins(int x,int y)
 13 {
 14     len++;
 15     a[len].x=x;a[len].y=y;
 16     a[len].next=last[x];last[x]=len;
 17 }
 18 struct edge
 19 {
 20     int x,y,next;
 21 }e[1110000];int len1,last1[510000];
 22 void inss(int x,int y)
 23 {
 24     len1++;
 25     e[len1].x=x;e[len1].y=y;
 26     e[len1].next=last1[x];last1[x]=len1;
 27 }
 28 int cnt,tp,id;
 29 int belong[510000],dfn[510000],low[510000],sta[510000],size[510000];
 30 bool v[510000];
 31 void dfs(int x)
 32 {
 33     low[x]=dfn[x]=++id;
 34     sta[++tp]=x;v[x]=true;
 35     for(int k=last[x];k;k=a[k].next)
 36     {
 37         int y=a[k].y;
 38         if(dfn[y]==-1)
 39         {
 40             dfs(y);
 41             low[x]=min(low[x],low[y]);
 42         }
 43         else
 44         {
 45             if(v[y]==true)
 46                 low[x]=min(low[x],dfn[y]);
 47         }
 48     }
 49     if(low[x]==dfn[x])
 50     {
 51         int i;cnt++;
 52         do{
 53             i=sta[tp--];
 54             v[i]=false;
 55             belong[i]=cnt;
 56             size[cnt]++;
 57         }while(i!=x);
 58     }
 59 }
 60 int ru[510000],chu[510000],sum1,sum2;
 61 bool check(int x)
 62 {
 63     if(size[x]!=1)return true;
 64     if(last1[x]==0)return false;
 65     for(int k=last1[x];k;k=e[k].next)
 66     {
 67         int y=e[k].y;
 68         if(ru[y]<=1)return true;
 69     }
 70     return false;
 71 }
 72 int main()
 73 {
 74     cnt=tp=id=sum1=sum2=0;
 75     len=0;len1=0;
 76     memset(last,0,sizeof(last));memset(last1,0,sizeof(last1));
 77     scanf("%d%d",&n,&m);
 78     memset(chu,0,sizeof(chu));
 79     memset(ru,0,sizeof(ru));
 80     memset(sta,0,sizeof(sta));
 81     memset(dfn,-1,sizeof(dfn));
 82     memset(low,0,sizeof(low));
 83     memset(v,false,sizeof(v));
 84     for(int i=1;i<=m;i++)
 85     {
 86         int x,y;
 87         scanf("%d%d",&x,&y);
 88         ins(x,y);
 89     }
 90     for(int i=1;i<=n;i++)
 91         if(dfn[i]==-1)
 92             dfs(i);
 93     for(int i=1;i<=m;i++)
 94     {
 95         int st=belong[a[i].x],ed=belong[a[i].y];
 96         if(st!=ed)
 97         {
 98             ru[ed]++;
 99             inss(st,ed);
100         }
101     }
102     for(int i=1;i<=cnt;i++)
103         if(ru[i]==0)sum1++;
104     for(int i=1;i<=cnt;i++)
105         if(ru[i]==0)
106             if(check(i)==false){sum1--;break;}
107     printf("%.6lf\n",1.0-double(sum1)/double(n));
108     return 0;
109 }

原文地址:https://www.cnblogs.com/CHerish_OI/p/8438040.html

时间: 2024-10-16 03:29:04

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

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

感觉今天状态起飞了!!!之前留的坑一调就A了,舒服!!! 那么这题之前一看就觉得,假如一个人没人认识实际上他必须查一下,那么我第一次做的时候就把他抽象成了很多棵树,然后我只查树根,然后下面的每一层我都知道身份,那就没有生命之忧了.然后特判一下有一个人没人认识tata也不认识别人,就是自己独立出来的,那他最后留下来实际上不用查. 然后实际上这题怎么可能这么简单,肯定会构环的,那么就考虑强连通缩点,那么这题难就难在怎么判最后查剩一个人的情况了,那么具体怎么做呢?首先这个点入度肯定为0的,再者这个联通

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

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

[中山市选2011]杀人游戏

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

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

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

[补档][中山市选2011]杀人游戏

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

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

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

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 杀人游戏 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 于