[Tarjan缩点][bitset]大包子玩游戏

题意是给你一个图。
每次你在剩下的点中随机选择一个点
这个点及其后继的点会被删除(包括边)
问你期望操作次数
如果对于一个点i有ai个点可以到达它
那么我们期望的操作次数为
i = 1 n 1 a i \sum_{i=1}^{n}\frac{1}{a_{i}}
可以用tarjan缩点后用bitset压位解决
时间复杂度:
O ( 1 32 n 3 ) O(\frac{1}{32}n^3)

#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<bitset>
#include<algorithm>
using namespace std;
int n;
#define Maxn 1005
#define E 1000010
int head[Maxn],v[E],nxt[E],tot=0;
int dfn[Maxn],low[Maxn],dfk=0;
int bel[Maxn],cnt=0;
int stk[Maxn],top=0;
vector<int> graph[Maxn];
int in[Maxn];
bool instack[Maxn];
int siz[Maxn];
bitset<Maxn> b[Maxn];
int Q[Maxn],hd,tl;
inline void add_edge(int s,int e){tot++;v[tot]=e;nxt[tot]=head[s];head[s]=tot;}
void tarjan(int u){
	dfn[u]=low[u]=++dfk;
	stk[++top]=u;instack[u]=true;
	for(int i=head[u];i;i=nxt[i])
		if(!dfn[v[i]])tarjan(v[i]),low[u]=min(low[u],low[v[i]]);
	    else if(instack[v[i]])low[u]=min(low[u],dfn[v[i]]);
	if(low[u]==dfn[u]){
		cnt++;
		b[cnt].reset();
		siz[cnt]=0;
		graph[cnt].clear();
		int x;
		do{
			siz[cnt]++;
			x=stk[top];
			top--;
		    bel[x]=cnt;
		    b[cnt].set(x);
		    instack[x]=false;
		}while(x!=u);
	}
}
int main(){
	int T;
	scanf("%d",&T);
	for(register int tt=1;tt<=T;++tt){
		top=0;
		memset(in,0,sizeof(in));
		memset(instack,false,sizeof(instack));
		tot=0;memset(head,0,sizeof(head));
		memset(dfn,0,sizeof(dfn));dfk=0;cnt=0;
	    scanf("%d",&n);
	    for(register int i=1;i<=n;++i){
		    int k,x;
		    scanf("%d",&k);
		    for(register int j=1;j<=k;++j){
			    scanf("%d",&x);
			    add_edge(i,x);
		    }
	    }
	    for(register int i=1;i<=n;++i)
	    	if(!dfn[i])tarjan(i);
	    for(register int i=1;i<=n;++i)
	    	for(int j=head[i];j;j=nxt[j])
	    		if(bel[i]!=bel[v[j]]){
	    			graph[bel[i]].push_back(bel[v[j]]);
	    			in[bel[v[j]]]++;
	    		}
	    hd=tl=0;
	    for(register int i=1;i<=cnt;++i)
	    	if(!in[i])Q[tl++]=i;
	    while(hd<tl){
	    	int u=Q[hd];
	    	hd++;
	    	for(int i=0;i<graph[u].size();++i){
	    		in[graph[u][i]]--;
	    		b[graph[u][i]]|=b[u];
	    		if(!in[graph[u][i]])Q[tl++]=graph[u][i];
	    	}
	    }
	    double ans=0;
	    for(register int i=1;i<=cnt;++i)ans+=1.0*siz[i]/b[i].count();
	    printf("Case #%d: %.5lf\n",tt,ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ezoilearner/article/details/82947070
今日推荐