[Tarjan縮點][bitset]大包子玩遊戲
阿新 • • 發佈:2018-12-13
題意是給你一個圖。 每次你在剩下的點中隨機選擇一個點 這個點及其後繼的點會被刪除(包括邊) 問你期望操作次數 如果對於一個點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; }