题意:
模板题,求图中每个割点能把网络分成几个点双连通分量(不是割点就输出他有几块即可)。
题解:
跟POJ 的SPF很像
这题用Tarjan来求,首先我们需要统计出来具体有几个连通块。
对于每个连通块,我们需要判断这个割点去掉后,这幅图会被分成几块?
这个其实很简单,只需要更改一下判断这个点是否为割点即可。
每被判断成一个割点,那么这个割点++。
注意特判根节点! 看看它有几个不相连的子树
num[]代表的是 从这个点分支出去,有几个不相连的子树
到最后的时候要进行num[i]--,是因为他是头节点。(画个图理解一下)
num[i]--;
/*Keep on going Never give up*/
//#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define Accepted 0
#define AK main()
#define I_can signed
using namespace std;
const int maxn =3e5+10;
const int MaxN = 0x3f3f3f3f;
const int MinN = 0xc0c0c00c;
typedef long long ll;
const int inf=0x3f3f3f3f;
const ll mod=1e9+7;
using namespace std;
vector<int> edge[maxn];
int n,m;
int low[maxn];
int num[maxn],dfn[maxn];
bool visited[maxn];
int cnt,top;
void dfs(int u,int fa){
visited[u]=true;
low[u]=dfn[u]=++cnt;
int ch=0;
for(int i=0;i<edge[u].size();i++){
int v=edge[u][i];
if(!visited[v]){
ch++;
dfs(v,u);
low[u]=min(low[v],low[u]);
if(low[v]>=dfn[u]) num[u]++;
}
else if(dfn[v]<dfn[u]&&v!=fa){
low[u]=min(dfn[v],low[u]);
}
}
// if(u==top&&ch>=1){
// num[u]=ch;
// }
}
I_can AK
{
//freopen("in.txt","r",stdin);
ios::sync_with_stdio(false);
memset(visited,false,sizeof visited);
cin>>n>>m;
for(int i=0;i<m;i++){
int u,v;
cin>>u>>v;
edge[u].push_back(v);
edge[v].push_back(u);
}
//dfs(1,-1);
int ans=0;
//cout<<visited[1]<<endl;
for(int i=1;i<=n;i++){
if(!visited[i]){
ans++;
//cout<<i<<endl;
top=i;
dfs(i,-1);
num[i]--;
}
}
//cout<<ans<<endl;
//cout<<num[1]<<endl;
for(int i=1;i<=n;i++){
cout<<num[i]+ans<<" ";
}
return 0;
}

京公网安备 11010502036488号