殺人遊戲[tarjan]
阿新 • • 發佈:2018-11-04
tarjan縮點,找入度為0的點(因為必須要查)的個數
同時如果有一個點入度為0,且它連如的點入度不為1,那麼把它放在最後查,就可以少查一次
#include<bits/stdc++.h> #define N 100005 #define M 300005*2 using namespace std; int first[N],next[M],to[M],tot; int dfn[N],low[N],sta[N],insta[N]; int id[N],siz[N],sign,top,cnt; int n,m,du[N],ans,flag; map<pair<int,int>,int >S; vector<int> V[N]; int read(){ int cnt=0,f=1;char ch=0; while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch))cnt=cnt*10+(ch-'0'),ch=getchar(); return cnt*f; } void add(int x,int y){ next[++tot]=first[x],first[x]=tot,to[tot]=y; } void dfs(int u){ dfn[u]=low[u]=++sign; sta[++top]=u,insta[u]=1; for(int i=first[u];i;i=next[i]){ int t=to[i]; if(!dfn[t]) dfs(t),low[u]=min(low[u],low[t]); else if(insta[t] && dfn[t]<low[u]) low[u]=dfn[t]; } if(dfn[u]==low[u]){ cnt++; do{ id[sta[top]]=cnt; siz[cnt]++; insta[sta[top]]=0; }while(sta[top--]!=u); } } int main(){ n=read(),m=read(); for(int i=1;i<=m;i++){ int x=read(),y=read(); add(x,y); } for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i); for(int i=1;i<=n;i++) for(int j=first[i];j;j=next[j]) if(id[i]!=id[to[j]]){ du[id[to[j]]]++; if(!S[make_pair(id[i],id[to[j]])]){ V[id[i]].push_back(to[j]); S[make_pair(id[i],id[to[j]])]=1; } } for(int i=1;i<=cnt;i++){ if(!flag && du[i]==0 && siz[i]==1){ int pd=0; for(int j=0;j<V[i].size();j++) if(du[V[i][j]]==1) pd=1; if(!pd) flag=1; } if(du[i]==0) ans++; } double Ans=1-double((ans-flag)*1.0)/n; printf("%0.6lf\n",Ans); return 0; }