[HAOI2006] 受歡迎的牛
阿新 • • 發佈:2018-04-01
AR bsp edge microsoft 10000+ 接下來 main body 一個點
首先對於一個強聯通分量內的所有牛來說,他們彼此都認為對方受歡迎,且對於這個強聯通分量內的牛A來說,假設它認為不在這個強連通分量內的一頭牛B是受歡迎的,那麽這個強聯通分量內的所有牛都認為牛B受歡迎。
我們用Tarjan算法求一遍SCC,把一個SCC縮成一個點,並添加連接不同SCC的邊,註意這條邊是一條反向邊,本來的邊由a->b,我們要添加的這條邊由scc[b]->scc[a],這樣做是為了方便之後的DFS,最後得到一個DAG。
接下來我們在這個DAG上從所有入度為0的scc開始DFS,並記錄DFS過程中訪問到的SCC個數記為cnt,如果DFS結束後cnt==scc_cnt,代表所有SCC都認為這個SCC是受歡迎的,則所有牛都認為這個SCC內的牛是受歡迎的,累計牛的個數進答案即可。
我們只需要從入度為0的SCC開始DFS,是因為假設有一條邊SCC_A->SCC_B,代表SCC_B認為SCC_A是受歡迎的,又因為圖是DAG,所以SCC_A一定不認為SCC_B是受歡迎的,那麽SCC_B一定無法達到被所有牛認為是受歡迎的條件,所以我們證明了入度不為0的SCC一定不會是解。
// q.c #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<stack> using namespace std; const int M=10000+10; int n,m,ans,cnt1,cnt2,dc,scc_cnt,scc[M],h1[M],h2[M],w[M],pre[M],low[M],in[M],out[M]; bool vis[M]; stack<int> s; struct Edge { int u,v,next; Edge():u(0),v(0),next(-1) {} }ed1[M*5],ed2[M*5]; void add_edge(int a,int b,bool flag) { if(flag) ed1[++cnt1].u=a,ed1[cnt1].v=b,ed1[cnt1].next=h1[a],h1[a]=cnt1; else in[b]++,out[a]++,ed2[++cnt2].u=a,ed2[cnt2].v=b,ed2[cnt2].next=h2[a],h2[a]=cnt2; } void dfs1(int u) { pre[u]=low[u]=++dc; s.push(u); for(int i=h1[u];i!=-1;i=ed1[i].next) { Edge p=ed1[i]; if(!pre[p.v]) { dfs1(p.v); low[u]=min(low[u],low[p.v]); } else if(!scc[p.v]) low[u]=min(low[u],low[p.v]); } if(low[u]==pre[u]) { ++scc_cnt; for(;;) { int x=s.top(); s.pop(); scc[x]=scc_cnt; if(x==u) break; } } } void dfs2(int u,int &d) { vis[u]=true; ++d; for(int i=h2[u];i!=-1;i=ed2[i].next) if(!vis[ed2[i].v]) dfs2(ed2[i].v,d); } int main() { freopen("cow.in","r",stdin); freopen("cow.out","w",stdout); memset(h1,-1,sizeof(h1)); memset(h2,-1,sizeof(h2)); scanf("%d%d",&n,&m); int a,b,tot; for(int i=1;i<=m;i++) { scanf("%d%d",&a,&b); add_edge(a,b,1); } for(int i=1;i<=n;i++) if(!pre[i]) dfs1(i); for(int i=1;i<=n;i++) w[scc[i]]++; for(int i=1;i<=cnt1;i++) { Edge p=ed1[i]; if(scc[p.u]!=scc[p.v]) add_edge(scc[p.v],scc[p.u],0); } for(int i=1;i<=scc_cnt;i++) if(!in[i]) { memset(vis,0,sizeof(vis)); dfs2(i,tot=0); if(tot==scc_cnt) ans+=w[i]; } printf("%d\n",ans); return 0; }
[HAOI2006] 受歡迎的牛