洛谷专题-强连通分量
P2341 [USACO03NOV][HAOI2006]受欢迎的牛 G /【模板】强连通分量
思路:
题目中问的是有多少牛受到所有牛的欢迎,因为本题具有传递性,则在图中,每个强连通分量中的奶牛都是互相喜欢的。所以,只要跑一遍Tarjan,图变成DAG有向无环图。
因为每一头奶牛都需要得到其他牛的欢迎,因此在没有环的情况下,不能再喜欢除了自环中的其它牛,即出度为0的牛是明星牛。
注意:特殊情况,如果存在一个以上的出度为0的点,则这几个子图中的奶牛都无法喜欢到其他这样子图中的奶牛(不连通)。所以输出0
#include<iostream> #include<algorithm> #include<cstring> #include<vector> #include<cstdio> using namespace std; const int maxn=1e5+10; vector<int> a[maxn]; int tot=0,t=0,k=0,dfs[maxn],low[maxn],stack[maxn],flag[maxn],color[maxn],cnt[maxn],out[maxn]; void tarjan(int x) { dfs[x]=low[x]=++tot; stack[++k]=x; flag[x]=1; for(int i=0;i<a[x].size();i++){ if(!dfs[a[x][i]]){ tarjan(a[x][i]); low[x]=min(low[x],low[a[x][i]]); } else if(flag[a[x][i]]) low[x]=min(low[x],dfs[a[x][i]]); } if(dfs[x]==low[x]){ t++; do{ color[stack[k]]=t,cnt[t]++; flag[stack[k--]]=0; }while(x!=stack[k+1]); } } int main() { int n,m,u,v; scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ scanf("%d%d",&u,&v); a[u].push_back(v); } for(int i=1;i<=n;i++) if(!dfs[i]) tarjan(i); for(int i=1;i<=n;i++){ for(int j=0;j<a[i].size();j++){ if(color[i]!=color[a[i][j]]) out[color[i]]++; } } int ans=0; for(int i=1;i<=t;i++){ if(out[i]==0){ if(ans){ cout<<0<<endl;return 0;} else ans=cnt[i]; } } cout<<ans<<endl; return 0; }
P3469 [POI2008]BLO-Blockade(求割点)
思路:
如果不是割点的话,答案就为2*(n-1)
是割点的话,答案就为∑sumi* (n-sum-1)+(n-sum-1)*sum+2*(n-1),sum为其dfs子树大小
#include<iostream> #include<algorithm> #include<vector> #include<cstdio> using namespace std; typedef long long ll; const int maxn=1e5+10; vector<int> a[maxn]; ll low[maxn],dfs[maxn],siz[maxn],tot; ll ans[maxn],n,flag[maxn]; ll tarjan(int x,int fa) { dfs[x]=low[x]=++tot; int sum=0,son=0; for(int i=0;i<a[x].size();i++){ int u=a[x][i]; if(u==fa) continue; if(!dfs[u]){ ll size=tarjan(u,x); son+=size; low[x]=min(low[x],low[u]); if(low[u]>=dfs[x]){ sum+=size; ans[x]+=size*(n-1-size); } } low[x]=min(low[x],dfs[u]); } ans[x]+=(n-sum-1)*sum; ans[x]+=2*(n-1); return son+1; } int main() { int m,u,v; scanf("%lld%d",&n,&m); for(int i=1;i<=m;i++){ scanf("%d%d",&u,&v); a[u].push_back(v); a[v].push_back(u); } tarjan(1,0); for(int i=1;i<=n;i++) printf("%lld\n",ans[i]); return 0; }