问题描述:给你一张无向图,求出图中割点的数目和每个割点所能划分的图的联通分量的数目
思路:套用模板
如果u是割点,成立条件有两个;
第一:u是根,并且u的孩子数目大于1。
第二:u不是根,并且存在至少一个子树v,使得lowv >= pre[u]。
割点u所对应的联通分量的个数等于多少?分为两种情况;
第一:u是根,数目就等于son。
第二:u不是根,数目就等于满足lowv >= pre[u]的u孩子的个数 + 1。
根据上述的割点的性质,套用模板就可以求出这道题了:
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cmath>
#include<vector>
#define pb push_back
using namespace std;
const int maxn = 1500;
int pre[maxn],cnt=0,iscut[maxn];
vector<int>G[maxn];
int dfs(int u,int fa)
{
int lowu = pre[u] = ++cnt;
int son = 0;
for(int i=0;i<G[u].size();i++)
{
int v = G[u][i];
if(!pre[v])
{
++son;
int lowv = dfs(v,u);
lowu = min(lowv,lowu);
if(lowv >= pre[u])++iscut[u];
}
else if(pre[v] < pre[u] && v != fa)
lowu = min(lowu,pre[v]);
}
if(fa<0 && son == 1)iscut[u] = 0;
else if(fa > 0 && iscut[u])++iscut[u];
return lowu;
}
int main()
{
int u,v,kase = 0;
while(~scanf("%d",&u)&&u)
{
for(int i=0;i<maxn;i++)iscut[i]=0,G[i].clear(),pre[i]=0;
cnt = 0;
scanf("%d",&v);
G[u].pb(v),G[v].pb(u);
while(~scanf("%d",&u)&&u)
{
scanf("%d",&v);
G[u].pb(v),G[v].pb(u);
}
if(kase++)puts("");
printf("Network #%d\n",kase);
dfs(1,-1);
int flag=1;
for(int i=1;i<maxn;i++)
{
if(iscut[i])
{
printf(" SPF node %d leaves %d subnets\n",i,iscut[i]);
flag=0;
}
}
if(flag)printf(" No SPF nodes\n");
}
return 0;
}
题目描述:求桥
跟求割点非常类似,求桥只需满足:low【v】> pre【u】。这个意思是,u的子节点v最多只能连回v自己。
#include <bits/stdc++.h>
#define pb push_back
#define mk make_pair
#define pi pair<int,int>
using namespace std;
const int maxn = 200;
int pre[maxn],cnt=0;
vector<int>G[maxn];
vector<pi>ans;
int dfs(int u,int fa)
{
int lowu = pre[u] = ++cnt;
for(int i=0;i<G[u].size();i++)
{
int v = G[u][i];
if(!pre[v]) //通过树边更新lowu
{
int lowv = dfs(v,u);
lowu = min(lowv,lowu);
if(lowv > pre[u]) {
ans.pb(mk(min(u,v),max(u,v)));
}
}
else if(pre[v] < pre[u] && v != fa) //通过反向边更新lowu
lowu = min(lowu,pre[v]);
}
return lowu;
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
while(m--)
{
int u,v;
scanf("%d%d",&u,&v);
G[u].pb(v),G[v].pb(u);
}
dfs(1,-1);
sort(ans.begin(),ans.end());
for(int i=0;i<ans.size();i++) {
cout<<ans[i].first<<' '<<ans[i].second<<'\n';
}
return 0;
}