-
B - Network
- UVA - 315
- 我们维护两个数组dfn[]和low[],dfn[u]表示顶点u第几个被(首次)访问,low[u]表示顶点u及其子树中的点,通过非父子边(回边),能够回溯到的最早的点(dfn最小)的dfn值(但不能通过连接u与其父节点的边)。对于边(u, v),如果low[v]>=dfn[u],此时u就是割点。
- 但这里也出现一个问题:怎么计算low[u]。
- 假设当前顶点为u,则默认low[u]=dfn[u],即最早只能回溯到自身。
- 有一条边(u, v),如果v未访问过,继续DFS,DFS完之后,low[u]=min(low[u], low[v]);
- 如果v访问过(且u不是v的父亲),就不需要继续DFS了,一定有dfn[v]<dfn[u],low[u]=min(low[u], dfn[v])。
- 转自:https://blog.csdn.net/duan_1998/article/details/76690536?utm_source=copy
- 图一:
这里的图一共有三个割点,编号分别是2 ,3,4,而去掉1或5,整个网络体系依旧是一个连通图。图二:
此时在图一上加了一条红线,也即是将2,4连通,那么此时3便不是割点了,因为去掉3之后,可以通过2->4将整个图连通。
如果用深搜的思想去写,那么需要一个起点,也可以称为根节点,最终,整个图都会被遍历一遍,假设在这里,设点1为根节点(谁都可以)(无向图),那么整个遍历顺序就是:1->2->3->4->5,这样标记了编号之后,深搜经过的边就会构成名叫:深搜优先生成树的树形结构(树形结构不会有环)。也即是每个点都有一个访问时刻(num数组),那么分析一下存在割点的情况:
第一种:假设当前点围割点,那么访问时刻比它大的点与访问时刻比他小的点之间没有联系。
对于这一种情况,图一中的点3符合,而图二的点3不符合,明显看到2-4有条线跳过了3,那么我们该怎么判断当前点有没有被跳过呢?(点的编号越小,越靠近根哦)
主要还是那条红线,这条线并没有出现在深搜优先生成树中,所以叫做:反祖边(回退边),也就是能够从先序编号较大的点直接回到编号较小的点,所以根据这条红线,弄了一个数组low,low[4]=min(low[4],num[2]),所以由这个数组记录可以知道,4最高是可以回到点2的,所以去掉点3无所谓,所以在整个代码中,先序编号(num数组)记录了是整个深度优先生成树,他是连通的,而low数组记录的是当前点可以返回到编号最小的那个点的先序编号,比较的时候呢,我们可以比较low数组,比如:low[3]>low[4],可知,点4可以比3更接近根,所以可以跳过3,也就是说,去掉3,4依旧可以与比3更高的点相连接,使网络连通。 - 图三:
那么,就像图三一样,如果真要一个个比较的话,也要比较low[3]与low[5]的关系,如果3的子节点有很多,那完了,铁定超时,所以我们可以直接把点3的所有子节点的low最小值赋给low[3],那样,当深搜回溯的时候,遇到3,如果此时low[3]是1(low[5]给的),那么和他自身的先序编号num[3]进行比较,说明他的子节点low的值有比它小的,也就是他的子节点与3上面的点有条边叫做反祖边(回退边),那说明3肯定不是割点。至于怎么赋值,可以在回溯的时候赋值呀。
但是呢,除此之外,还要特判这个点不是根节点,因为没有编号比根节点更小的了。。。你说是吧。。。
所以根节点还需要特判,怎么特判呢?
既然是树形结构,那么不存在环,所以当根节点的儿子数量大于1的时候,就说明他是割点了 -
#include<bits/stdc++.h> using namespace std; #define maxn 10010 int dfn[maxn],low[maxn],sum,n; int parent[maxn],ans[maxn],cnt; vector<int>mmp[maxn]; bool vis[maxn],check[maxn]; void dfs(int u) { int children=0; dfn[u]=low[u]=++cnt; vis[u]=true; int len=mmp[u].size(); for(int i=0; i<len; i++) { int v=mmp[u][i]; if(!vis[v]) { children++; parent[v]=u; dfs(v); low[u]=min(low[u],low[v]); if(parent[u]==-1&&children>=2&&!check[u]) { sum++; check[u]=1; } else if(parent[u]!=-1&&low[v]>=dfn[u]&&!check[u]) { sum++; check[u]=1; } } else if(v!=parent[u]) low[u]=min(low[u],dfn[v]); } } int main() { while(~scanf("%d",&n)&&n) { memset(low,0,sizeof(low)); memset(parent,-1,sizeof(parent)); memset(dfn,0,sizeof(dfn)); memset(vis,0,sizeof(vis)); memset(check,0,sizeof(check)); for(int i=1; i<=n; i++) mmp[i].clear(); int a,c; while(~scanf("%d",&a)&&a) { while(getchar()!='\n') { scanf("%d",&c); mmp[a].push_back(c); mmp[c].push_back(a); } } cnt=sum=0; dfs(1); printf("%d\n",sum); } return 0; }
B - Network UVA - 割点模板
最新推荐文章于 2020-07-21 18:38:49 发布