bzoj 2438 殺人遊戲(tarjan縮點)
阿新 • • 發佈:2018-12-13
根據題意只要找出有多少個不連通的集合就可以了。。但是在判定的時候有環的話會有點麻煩,所以先縮點,在dfs。
但是如果有一個點它的所有連的點不止它一個入度的話 ,而且這個點的入度為0,那麼最後剩它的時候就不用問了。
#include<cstdio> #include<cmath> #include<algorithm> #include<cstring> using namespace std; struct node { int to; int nxt; }edge[300005],edge1[300005]; int head[100005],head1[100005]; int cnt=1,ans,cot=1,gs[100005]; void init() { memset(head,-1,sizeof(head)); memset(head1,-1,sizeof(head1)); } void add(int from,int to) { edge[cnt].to=to; edge[cnt].nxt=head[from]; head[from]=cnt++; } void added(int from,int to) { edge1[cot].to=to; edge1[cot].nxt=head1[from]; head1[from]=cot++; } int dfn[100005]; int low[100005]; int srcnt; int pos[100005]; int srans[100005]; int deep=0; int top; int stackk[100005]; int used[100005]; int out[100005],outt[100005]; void tarjan(int rt) { dfn[rt] = low[rt] = ++deep; stackk[++top] = rt; for(int i = head[rt];i != -1;i = edge[i].nxt) { int to = edge[i].to; if(dfn[to] == 0) { tarjan(to); low[rt] = min(low[rt],low[to]); }else if(pos[to] == 0) { low[rt] = min(low[rt],dfn[to]); } } if(low[rt] == dfn[rt]) { int v = 0; int t = 0; srcnt++; while(v != rt) { v = stackk[top]; top--; t++; pos[v] = srcnt; } srans[srcnt] = t; } } void dfs(int u,int ttt) { used[u]=ttt; for(int i=head1[u];i!=-1;i=edge1[i].nxt) { int to=edge1[i].to; dfs(to,ttt); } } int main() { int n,m; scanf("%d%d",&n,&m); init(); for(int i=1;i<=m;i++) { int a,b; scanf("%d%d",&a,&b); add(a,b); outt[b]++; } for(int i=1;i<=n;i++) { if(!dfn[i]) { tarjan(i); } } for(int i=1;i<=n;i++) { for(int j=head[i];j!=-1;j=edge[j].nxt) { int to=edge[j].to; if(pos[i]!=pos[to]) { added(pos[i],pos[to]); out[pos[to]]++; } } } for(int i=1;i<=srcnt;i++) { if(!out[i])dfs(i,i); } for(int i=1;i<=srcnt;i++) { if(used[i]==i) { ans++; } gs[used[i]]++; } int flag=0; for(int i=1;i<=n;i++) { if(!outt[i]) { for(int j=head[i];j!=-1;j=edge[j].nxt) { int to=edge[j].to; if(outt[to]==1) { flag=1;break; } } if(!flag) { ans--;break; }else { flag=0; } } } double tt=(double)(n-ans)/(double)n; printf("%.6lf",tt); return 0; }