HDU-3177 Redundant Paths 无向图双连通
来源:互联网 发布:王者荣耀mvp新算法 编辑:程序博客网 时间:2024/06/05 06:47
http://poj.org/problem?id=3177
/*大致题意: 为了保护放牧环境,避免牲畜过度啃咬同一个地方的草皮,牧场主决定利用不断迁移牲畜进行喂养的方法去保护牧草。然而牲畜在迁移过程中也会啃食路上的牧草,所以如果每次迁移都用同一条道路,那么该条道路同样会被啃咬过度而遭受破坏。 现在牧场主拥有F个农场,已知这些农场至少有一条路径连接起来(不一定是直接相连),但从某些农场去另外一些农场,至少有一条路可通行。为了保护道路上的牧草,农场主希望再建造若干条道路,使得每次迁移牲畜时,至少有2种迁移途径,避免重复走上次迁移的道路。已知当前有的R条道路,问农场主至少要新建造几条道路,才能满足要求? 解题思路:“使得每次迁移牲畜时,至少有2种迁移途径,避免重复走上次迁移的道路。”就是说当吧F个农场看作点、路看作边构造一个无向图G时,图G不存在桥。 那么可以建立模型: 给定一个连通的无向图G,至少要添加几条边,才能使其变为双连通图。2.求双连通分量以及构造双连通分量:http://blog.csdn.net/lyy289065406/article/details/6762432对于点双连通分支,实际上在求割点的过程中就能顺便把每个点双连通分支求出。建立一个栈,存储当前双连通分支,在搜索图时,每找到一条树枝边或后向边(非横叉边),就把这条边加入栈中。如果遇到某时满足DFS(u)<=Low(v),说明u是一个割点,同时把边从栈顶一个个取出,直到遇到了边(u,v),取出的这些边与其关联的点,组成一个点双连通分支。割点可以属于多个点双连通分支,其余点和每条边只属于且属于一个点双连通分支。对于边双连通分支,求法更为简单。只需在求出所有的桥以后,把桥边删除,原图变成了多个连通块,则每个连通块就是一个边双连通分支。桥不属于任何一个边双连通分支,其余的边和每个顶点都属于且只属于一个边双连通分支。一个有桥的连通图,如何把它通过加边变成边双连通图?方法为首先求出所有的桥,然后删除这些桥边,剩下的每个连通块都是一个双连通子图。把每个双连通子图收缩为一个顶点,再把桥边加回来,最后的这个图一定是一棵树,边连通度为1。统计出树中度为1的节点的个数,即为叶节点的个数,记为leaf。则至少在树上添加(leaf+1)/2条边,就能使树达到边二连通,所以至少添加的边数就是(leaf+1)/2。具体方法为,首先把两个最近公共祖先最远的两个叶节点之间连接一条边,这样可以把这两个点到祖先的路径上所有点收缩到一起,因为一个形成的环一定是双连通的。然后再找两个最近公共祖先最远的两个叶节点,这样一对一对找完,恰好是(leaf+1)/2次,把所有点收缩到了一起。*/#include<stdio.h>#include<string.h>#include<vector>using namespace std;const int maxn = 1005;const int inf = 1<<30;int n,m;int time,ans;int low[maxn],dfn[maxn],cut[maxn];bool vis[maxn][maxn];vector<int>map[maxn];void tarjan( int u, int fa ){ low[u] = dfn[u] = ++time; for( int i = 0; i < map[u].size(); i ++ ) { int v = map[u][i]; if( v == fa ) //判定回边 continue; if( !dfn[v] ) { tarjan( v,u ); low[u] = low[u] <= low[v] ? low[u]:low[v]; } else low[u] = low[u] <= dfn[v] ? low[u]:dfn[v]; }}void output(){memset( cut,0,sizeof(cut) );int num = 0;for( int i = 1; i <= n; i++ ){for( int j = 0; j < map[i].size(); j ++ ) //计算每个点的度数{int v = map[i][j];if( low[v] != low[i] ) //不属于同一个块{cut[low[i]] ++;}}}for( int i = 0; i <= n; i ++ ) //计算度数为一的点数{if( cut[i] == 1 )num ++;}printf("%d\n",(num+1)/2);}void init() //初始化{ time = 0,ans = inf; for( int i = 1; i <= n; i ++ ) { map[i].clear(); } memset( low,0,sizeof(low) ); memset( dfn,0,sizeof(dfn) );}int main(){ int u,v,d; while( scanf("%d%d",&n,&m) != EOF ) { init(); for( int i = 1; i <= m; i ++ ) { scanf("%d%d",&u,&v); if( !vis[u][v] ) { map[u].push_back(v); map[v].push_back(u); vis[u][v] = vis[v][u] = 1; } } tarjan(1,1); output(); } return 0;}
//并查集版#include<stdio.h>#include<string.h>#include<vector>using namespace std;const int maxn = 1005;const int inf = 1<<30;int n,m;int time;int low[maxn],dfn[maxn],p[maxn];int bridge[maxn][2],bridge_n;int inq[maxn];vector<int>map[maxn];int find( int x ){return p[x] == x?x:p[x] = find(p[x]);}void merge( int a,int b ){int x = find(a);int y = find(b);if( x == y )return;p[y] = x;}void tarjan( int u, int fa ){int son = 0; //平行边 low[u] = dfn[u] = ++time; for( int i = 0; i < map[u].size(); i ++ ) { int v = map[u][i]; if( v == fa ) //判定回边 son ++; if( !dfn[v] ) { tarjan( v,u ); low[u] = low[u] <= low[v] ? low[u]:low[v];if( !(low[v] > dfn[u]) ) //缩点{merge(v,u);}else{bridge[++bridge_n][0] = u; //存割边bridge[bridge_n][1] = v;} } else if( v != fa || son != 1 ) low[u] = low[u] <= dfn[v] ? low[u]:dfn[v]; }}void output(){memset( inq,0,sizeof(inq) );int ans = 0;for( int i = 1; i <= bridge_n; i++ ) //割边两端的块度数加加{int a = find( bridge[i][0] );int b = find( bridge[i][1] );inq[a] ++;inq[b] ++;}for( int i = 1; i <= n; i ++ ) //计算度数为一的块数{if( inq[i] == 1 )ans ++;}printf("%d\n",(ans+1)/2);}void init() //初始化{ time = 0,bridge_n = 0; for( int i = 1; i <= n; i ++ ) { map[i].clear();p[i] = i; }memset( bridge,0,sizeof(bridge) ); memset( low,0,sizeof(low) ); memset( dfn,0,sizeof(dfn) );}int main(){ int u,v,d; while( scanf("%d%d",&n,&m) != EOF ) { init(); for( int i = 1; i <= m; i ++ ) { scanf("%d%d",&u,&v); map[u].push_back(v); map[v].push_back(u); } tarjan(1,1); output(); } return 0;}
- HDU-3177 Redundant Paths 无向图双连通
- poj3177 Redundant Paths 无向图 双连通分量 桥
- 【Redundant Paths】【无向图】【双连通分量】【缩点】
- PKU 3177 Redundant Paths - 无向图的双连通分量和桥
- POJ 3177--Redundant Paths【无向图增加最少的边成为边双连通图 && tarjan求ebc && 缩点构造缩点树】
- poj 3177 Redundant Paths 【无向图增加最少的边是图成为边—双连通】【tarjan求EBC + 缩点 统计度数为1的EBC】
- poj 3177 Redundant Paths 边双连通
- poj 3177 Redundant Paths 边双连通
- POJ 3177 Redundant Paths (双连通)
- poj 3177 Redundant Paths (双连通)
- poj 3177 Redundant Paths(构造边双连通)
- POJ -- 3177 Redundant Paths(边双连通)
- [POJ 3177]Redundant Paths[边双连通][Tarjan][缩点]
- poj 3177 Redundant Paths 【图论-边双连通】
- POJ 3177 Redundant Paths 无向图割边 + 缩点
- POJ 3352 Road Construction POJ 3177 Redundant Paths(边双连通图 Tarjan+缩点)
- 【连通图|边双连通+缩点】POJ-3177 Redundant Paths
- poj 3177 Redundant Paths(求最少加几条边将图变为边双连通图)
- 判断是否为二分图 染色法
- C++中四种类型转换方式
- hdu - 4738 Caocao's Bridges 割边
- 几行代码看程序员的水平——Android文件命名规范
- HDU - 2586 LCA
- HDU-3177 Redundant Paths 无向图双连通
- poj 2942 圆桌武士 双连通分量(BCC)+二分图+奇圈判断
- POJ-1144 Network 求割点
- OpenWrt学习笔记_DB120或rg100a刷机常用账号密码
- Tarjan算法
- POJ 1948 Triangular Pastures 解题报告
- poj-1273 Drainage Ditches 最大流
- radar(nyoj287贪心)
- Solar V5.0 Source