Bridges Gym - 100712H 无向图的边双连通分量,Tarjan缩点
http://codeforces.com/gym/100712/attachments
题意是给定一个无向图,要求添加一条边,使得最后剩下的桥的数量最小。
注意到在环中加边是无意义的。
那么先把环都缩成一个点,然后重新建立一颗树,找出树的直径就好。
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <assert.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL; #include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <bitset>
const int maxn = 1e5 + ;
struct Edge {
int u, v, tonext;
}e[maxn * ], tree[maxn * ];
int first[maxn], num;
int first_tree[maxn], num_tree;
void addEdge(int u, int v) {
++num;
e[num].u = u, e[num].v = v, e[num].tonext = first[u];
first[u] = num;
}
int DFN[maxn], low[maxn], when, st[maxn], top;
int id[maxn], toSelid;
bool vis[maxn];
void tarjan(int cur, int fa) {
DFN[cur] = low[cur] = ++when; //时间戳
st[++top] = cur; //进栈
vis[cur] = true;
for (int i = first[cur]; i; i = e[i].tonext) {
int v = e[i].v;
if (v == fa) continue;
if (!DFN[v]) { //没访问过
tarjan(v, cur);
low[cur] = min(low[cur], low[v]);
} else if (vis[v]) { // 访问过,而且还在栈里
low[cur] = min(low[cur], DFN[v]);
}
}
if (low[cur] == DFN[cur]) { //这个是强连通分量的根节点。
++toSelid;
do {
id[st[top]] = toSelid; //块id
// sum[toSelId]++; //id节点个数
// printf("%d ", st[top]);
vis[st[top]] = false;
top--;
} while (cur != st[top + ]);
// printf("\n");
}
} void solveTarjan(int n) {
memset(DFN, , sizeof DFN);
memset(low, , sizeof low);
memset(vis, , sizeof vis);
when = top = toSelid = ;
for (int i = ; i <= n; ++i) {
if (!DFN[i]) tarjan(i, i);
}
}
void addEdgeTree(int u, int v) {
++num_tree;
tree[num_tree].u = u, tree[num_tree].v = v, tree[num_tree].tonext = first_tree[u];
first_tree[u] = num_tree;
} struct bfsnode {
int cur, cnt;
bfsnode(int _cur, int _cnt) {
cur = _cur;
cnt = _cnt;
}
};
int tree_diameter(int begin, bool flag) {
memset(vis, , sizeof vis);
queue<struct bfsnode> que;
while (!que.empty()) que.pop();
que.push(bfsnode(begin, ));
vis[begin] = true;
int to = begin, mx = ;
while (!que.empty()) {
struct bfsnode t = que.front();
que.pop();
for (int i = first_tree[t.cur]; i; i = tree[i].tonext) {
int v = tree[i].v;
if (vis[v]) continue;
vis[v] = true;
que.push(bfsnode(v, t.cnt + ));
if (mx < t.cnt + ) {
to = v;
mx = t.cnt + ;
}
}
}
if (flag) return mx;
else return to;
} void work() {
memset(first, , sizeof first);
memset(first_tree, , sizeof first_tree);
num = num_tree = ;
int n, m;
scanf("%d%d", &n, &m);
for (int i = ; i <= m; ++i) {
int u, v;
scanf("%d%d", &u, &v);
addEdge(u, v);
addEdge(v, u);
}
solveTarjan(n);
// for (int i = 1; i <= n; ++i) {
// cout << id[i] << " ";
// }
for (int i = ; i <= n; ++i) {
for (int j = first[i]; j; j = e[j].tonext) {
int v = e[j].v;
if (id[i] == id[v]) continue;
addEdgeTree(id[i], id[v]);
addEdgeTree(id[v], id[i]);
}
}
int res = tree_diameter(, );
int di = tree_diameter(res, );
int ans = toSelid - di - ;
ans = max(ans, );
cout << ans << endl;
} int main() {
#ifdef local
freopen("data.txt", "r", stdin);
// freopen("data.txt", "w", stdout);
#endif
int t;
scanf("%d", &t);
while (t--) work();
return ;
}
Bridges Gym - 100712H 无向图的边双连通分量,Tarjan缩点的更多相关文章
- tarjan算法与无向图的连通性(割点,桥,双连通分量,缩点)
基本概念 给定无向连通图G = (V, E)割点:对于x∈V,从图中删去节点x以及所有与x关联的边之后,G分裂为两个或两个以上不相连的子图,则称x为割点割边(桥)若对于e∈E,从图中删去边e之后,G分 ...
- tarjan算法求无向图的桥、边双连通分量并缩点
// tarjan算法求无向图的桥.边双连通分量并缩点 #include<iostream> #include<cstdio> #include<cstring> ...
- 点/边 双连通分量---Tarjan算法
运用Tarjan算法,求解图的点/边双连通分量. 1.点双连通分量[块] 割点可以存在多个块中,每个块包含当前节点u,分量以边的形式输出比较有意义. typedef struct{ //栈结点结构 保 ...
- HDU4612Warm up 边双连通 Tarjan缩点
N planets are connected by M bidirectional channels that allow instant transportation. It's always p ...
- POJ 3352 无向图边双连通分量,缩点,无重边
为什么写这道题还是因为昨天多校的第二题,是道图论,HDU 4612. 当时拿到题目的时候就知道是道模版题,但是苦于图论太弱.模版都太水,居然找不到. 虽然比赛的时候最后水过了,但是那个模版看的还是一知 ...
- 无向图的边双连通分量(EBC)
嗯,首先边双连通分量(双连通分量之一)是:在一个无向图中,去掉任意的一条边都不会改变此图的连通性,即不存在桥(连通两个边双连通分量的边),称作边双连通分量.一个无向图的每一个极大边双连通子图称作此无向 ...
- [HDOJ4612]Warm up(双连通分量,缩点,树直径)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4612 所有图论题都要往树上考虑 题意:给一张图,仅允许添加一条边,问能干掉的最多条桥有多少. 必须解决 ...
- 无向图的点双连通分量(tarjan模板)
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #i ...
- UOJ#30/Codeforces 487E Tourists 点双连通分量,Tarjan,圆方树,树链剖分,线段树
原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ30.html 题目传送门 - UOJ#30 题意 uoj写的很简洁.清晰,这里就不抄一遍了. 题解 首先建 ...
随机推荐
- servlet过滤器Filter(理论篇)
为了减少servlet容器在服务器端对信息的判断量,产生了servlet过滤器. servlet过滤器是在java servlet规范2.3中定义的,他能够对servlet容器的请求和响应对象进行检查 ...
- tensorflow 线性回归解决 iris 2分类
# Combining Everything Together #---------------------------------- # This file will perform binary ...
- WebApi发送HTML表单数据:文件上传与多部分MIME
5.3 Sending HTML Form Data5.3 发送HTML表单数据(2) 本文引自:http://www.cnblogs.com/r01cn/archive/2012/12/20/282 ...
- 进程优先级、nice值
进程cpu资源分配就是指进程的优先权(priority).优先权高的进程有优先执行权利.配置进程优先权对多任务环境的linux很有用,可以改善系统性能.还可以把进程运行到指定的CPU上,这样一来,把不 ...
- [ZJOI 2007] 捉迷藏
[题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=1095 [算法] 首先建出点分树,然后每一个点开两个堆.“第一个堆记录子树中所有节点到 ...
- POJ3261(后缀数组+2分枚举)
Milk Patterns Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 12972 Accepted: 5769 Ca ...
- hihoCoder2月29日(字符串模拟)
时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 给定两个日期,计算这两个日期之间有多少个2月29日(包括起始日期). 只有闰年有2月29日,满足以下一个条件的年份为闰年: ...
- io_service work 的作用
当有任务的时候,run函数会一直阻塞:但当没有任务了,run函数会返回,所有异步操作终止. 客户端程序中,如果我想连接断开后重连,由于连接断开了,run会返回,当再次重连的时候,由于run返回了,即使 ...
- ununtu 下安装 Nvidia 显卡驱动
本人电脑硬件配置:CPU : AMD Athlon(tm) II X2 215 Processor × 2 显示卡 : GeForce 6150SE nForce 430/integrated/SSE ...
- linux中消息队列<一>
1 概念 (1)链表式结构组织,存放于内核. (2)通过队列标识来引用. (3)通过一个消息类型来索引指定的数据 2 创建消息队列 #include <sys/msg.h> int msg ...