P4819 [中山市选]杀人游戏
分析:
这种题先从简单情况分析:如果是一条链:1->2->3->4
直接查入度为0的即可:因为知道1,就知道2,如果2是杀手,结束。
否则去查证2(因为已知2不是杀手 所以这一步是不需要花费被杀的风险的!!)
以此类推。
最后的答案就是1-(1/n)*ans
一条链只需要查一个入度为0的点,那么如果有一个孤立的环呢?
显然需要查环中任意一个点即可。所以可以用tarjan缩点后,求入度为0的点即可。
但是这道题还有很多其他的坑:
eg:100 0
如果前99个人都查完了,第100个人就可以不用查了
考虑什么时候可以不用查:当一个点入度为0,并且它连的所有点入度都不为1(也就是说其他点可以通过另一个入度为0的点查到)
并且它的siz==1(是一个孤立的点,否则环中必须查一个点)
特判一下即可。
#include<bits/stdc++.h> using namespace std; #define ri register int #define N 100005 int n,m,dfn[N],low[N],stk[N],flag[N],bel[N],ru[N],Ti=0,tot=0,top=0,siz[N]; vector<int> e[N]; vector<int> h[N]; void tarjan(int u) { dfn[u]=low[u]=++Ti; stk[++top]=u; flag[u]=1; for(ri i=0;i<e[u].size();++i){ int v=e[u][i]; if(!dfn[v]){ tarjan(v); low[u]=min(low[u],low[v]); } else if(flag[v]) low[u]=min(low[u],dfn[v]); } if(dfn[u]==low[u]){ tot++; do{ int tmp=stk[top]; flag[tmp]=0; bel[tmp]=tot; siz[tot]++; }while(stk[top--]!=u); } } int main() { scanf("%d%d",&n,&m); int a,b; for(ri i=1;i<=m;++i) scanf("%d%d",&a,&b),e[a].push_back(b); for(ri i=1;i<=n;++i) if(!dfn[i]) tarjan(i); for(ri i=1;i<=n;++i){ for(ri j=0;j<e[i].size();++j){ int v=e[i][j]; if(bel[i]==bel[v]) continue; h[bel[i]].push_back(bel[v]); ru[bel[v]]++; } } int fl=0,ans=0; for(ri i=1;i<=tot;++i) if(!ru[i]){ ans++; if(fl || siz[i]>1) continue; fl=1; for(ri j=0;j<h[i].size();++j) if(ru[h[i][j]]<2) { fl=0; break;} } //printf("%d ",ans-fl); printf("%.6lf ",(1-(1.0/n)*(double)(ans-fl))); return 0; } /* 6 5 1 2 1 3 4 2 5 2 6 2 4 3 1 2 2 3 3 4 */