题意是给你一个图。
每次你在剩下的点中随机选择一个点
这个点及其后继的点会被删除(包括边)
问你期望操作次数
如果对于一个点i有ai个点可以到达它
那么我们期望的操作次数为
可以用tarjan缩点后用bitset压位解决
时间复杂度:
#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;
}