杀人游戏[中山市选2011]
题目描述
一位冷血的杀手潜入 Na-wiat,并假装成平民。警察希望能在 N 个人里面,
查出谁是杀手。
警察能够对每一个人进行查证,假如查证的对象是平民,他会告诉警察,他
认识的人, 谁是杀手, 谁是平民。 假如查证的对象是杀手, 杀手将会把警察干掉。
现在警察掌握了每一个人认识谁。
每一个人都有可能是杀手,可看作他们是杀手的概率是相同的。
问:根据最优的情况,保证警察自身安全并知道谁是杀手的概率最大是多
少?
输入
第一行有两个整数 N,M。
接下来有 M 行,每行两个整数 x,y,表示 x 认识 y(y 不一定认识 x,例如敬爱的胡爷爷) 。
输出
仅包含一行一个实数,保留小数点后面 6 位,表示最大概率。
样例输入
5 4
1 2
1 3
1 4
1 5
样例输出
0.800000
提示
警察只需要查证 1。假如1是杀手,警察就会被杀。假如 1不是杀手,他会告诉警
察 2,3,4,5 谁是杀手。而 1 是杀手的概率是 0.2,所以能知道谁是杀手但没被杀的概
率是0.8。对于 100%的数据有 1≤N ≤ 10 0000,0≤M ≤ 30 0000
【题解】
看了提示也没参悟到调查的未知身份人越少,危险越小这个道理。虽然刚开始是有这样的意识的,但是后来走上了一条名为“推式子”的不归路,然后就……有我这样的队友,警察是非阵亡不可啊。
所谓的概率题,除了最后结果是个double型还和概率有什么关系?!其实是个tarjan缩点题。凡是成环的,只要调查其中一个人就可以了。最关键的是其中一种特殊情况,有一个点完全孤立或有一个点没有入度且出度全都被别的点调查过,就没有调查他的必要了。考试后期想这个情况是否可行想了很久,没有个所以然。到底是在疑虑什么啊这种明显符合生活常理的情况,警察叔叔非阵亡不可+1。最大概率题,并不能拘泥于式子,毕竟大多数式子都是完全客观完全平均地选择各种方案,而这道题明显是涉及到方案选择的。
#include<iostream> #include<cstdio> #include<stack> #include<cstring> using namespace std; const int sj=100010; int n,m,e1,e2,h[sj],l[sj],a1,a2,dfn[sj],low[sj],c[sj]; int s[sj],cnt,fa[sj],bi,hz,su[sj],cd[sj],rd[sj]; bool r[sj]; struct B { int ne,v,u; }b[sj*3]; struct T { int ne,v; }t[sj*3]; void ad1(int x,int y) { b[e1].v=y; b[e1].u=x; b[e1].ne=h[x]; h[x]=e1++; } void ad2(int x,int y) { t[e2].v=y; t[e2].ne=l[x]; l[x]=e2++; } void init() { scanf("%d%d",&n,&m); memset(h,-1,sizeof(h)); memset(l,-1,sizeof(l)); for(int i=1;i<=m;i++) { scanf("%d%d",&a1,&a2); ad1(a1,a2); } for(int i=1;i<=n;i++) fa[i]=i; } int bj(int x,int y) { return x<y?x:y; } void tarjan(int x) { dfn[x]=low[x]=++cnt; s[++bi]=x; r[x]=1; int to; for(int i=h[x];i!=-1;i=b[i].ne) { to=b[i].v; if(!dfn[to]) { tarjan(to); low[x]=bj(low[x],low[to]); } else if(r[to]) low[x]=bj(low[x],dfn[to]); } if(low[x]==dfn[x]) { hz++; do { to=s[bi]; bi--; r[to]=0; su[hz]++; c[to]=hz; }while(to!=x); } } int jg; bool gl,kx; int main() { init(); for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); for(int i=0;i<e1;i++) if(c[b[i].u]!=c[b[i].v]) { ad2(c[b[i].u],c[b[i].v]); cd[c[b[i].u]]++; rd[c[b[i].v]]++; } for(int i=1;i<=hz;i++) { if(!rd[i]) jg++; kx=1; if(!gl&&!rd[i]&&su[i]==1) { for(int j=l[i];j!=-1;j=t[j].ne) if(rd[t[j].v]==1) kx=0; if(kx) gl=1; } } if(gl) jg--; printf("%.6lf",(double)(n-jg)/n); return 0; }