1. 程式人生 > >bzoj 2438 殺人遊戲(tarjan縮點)

bzoj 2438 殺人遊戲(tarjan縮點)

 根據題意只要找出有多少個不連通的集合就可以了。。但是在判定的時候有環的話會有點麻煩,所以先縮點,在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;
}