题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4612

所有图论题都要往树上考虑

题意:给一张图,仅允许添加一条边,问能干掉的最多条桥有多少。

必须解决重边的问题,最后会说。

首先tarjan跑出所有的双连通分量和是桥的边还有桥的数量,这非常重要。接着缩点重新建图,然后两遍dfs找出两个在树上距离最远的点。我的想法就是把这条最长的链连成一个环,让它成为一个双连通分量,这样的效果是最好的。最后就是用桥的数量减去树直径再减一就得到了剩下的桥的数量了。求树直径的时候重用了dfn数组,不要以为是错的就好。

重边真的好烦人啊,我像处理离散化那样unique了一下,发现是不可行的。最终还是参考了bin神的方法,在边的结构体里加一个记号来标记这个边是不是重边,也就是出现重边的话,那这几条重边就不是桥啦。如果按照我之前的做法,重边会被删掉,所以桥的数量会增多,显然是不对的。

 /*
━━━━━┒ギリギリ♂ eye!
┓┏┓┏┓┃キリキリ♂ mind!
┛┗┛┗┛┃\○/
┓┏┓┏┓┃ /
┛┗┛┗┛┃ノ)
┓┏┓┏┓┃
┛┗┛┗┛┃
┓┏┓┏┓┃
┛┗┛┗┛┃
┓┏┓┏┓┃
┛┗┛┗┛┃
┓┏┓┏┓┃
┃┃┃┃┃┃
┻┻┻┻┻┻
*/
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <climits>
#include <complex>
#include <fstream>
#include <cassert>
#include <cstdio>
#include <bitset>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <ctime>
#include <set>
#include <map>
#include <cmath>
using namespace std;
#define fr first
#define sc second
#define cl clear
#define BUG puts("here!!!")
#define W(a) while(a--)
#define pb(a) push_back(a)
#define Rint(a) scanf("%d", &a)
#define Rll(a) scanf("%lld", &a)
#define Rs(a) scanf("%s", a)
#define Cin(a) cin >> a
#define FRead() freopen("in", "r", stdin)
#define FWrite() freopen("out", "w", stdout)
#define Rep(i, len) for(int i = 0; i < (len); i++)
#define For(i, a, len) for(int i = (a); i < (len); i++)
#define Cls(a) memset((a), 0, sizeof(a))
#define Clr(a, x) memset((a), (x), sizeof(a))
#define Full(a) memset((a), 0x7f7f, sizeof(a))
#define lp p << 1
#define rp p << 1 | 1
#define pi 3.14159265359
#define RT return
typedef long long LL;
typedef long double LD;
typedef unsigned long long ULL;
typedef pair<int, int> pii;
typedef pair<string, int> psi;
typedef map<string, int> msi;
typedef vector<int> vi;
typedef vector<LL> vl;
typedef vector<vl> vvl;
typedef vector<bool> vb; const int maxn = ;
const int maxm = ; typedef struct Edge {
int u, v;
int next;
bool cut, r;
Edge() { next = -; cut = ; }
}Edge; typedef struct Tmp {
int u, v;
Tmp() {}
Tmp(int uu, int vv) : u(uu), v(vv) {}
bool operator==(Tmp p) { RT u == p.u && v == p.v; }
}Tmp; int head[maxn], ecnt;
int n, m;
int bcnt, idx;
int dfn[maxn], low[maxn];
int stk[maxn], top;
int belong[maxn];
bool instk[maxn];
Edge edge[maxm];
Tmp tmp[maxm];
vector<int> G[maxn]; bool cmp(Tmp x, Tmp y) {
if(x.u == y.u) RT x.v < y.v;
RT x.u < y.u;
} void init() {
memset(edge, , sizeof(edge));
memset(head, -, sizeof(head));
memset(instk, , sizeof(instk));
memset(dfn, , sizeof(dfn));
memset(low, , sizeof(low));
memset(belong, , sizeof(belong));
ecnt = top = bcnt = idx = ;
} void adde(int uu, int vv, bool p) {
edge[ecnt].u = uu;
edge[ecnt].v = vv;
edge[ecnt].cut = ;
edge[ecnt].r = p;
edge[ecnt].next = head[uu];
head[uu] = ecnt++;
} void tarjan(int u, int p, int r) {
int v = u;
dfn[u] = low[u] = ++idx;
stk[++top] = u;
instk[u] = ;
for(int i = head[u]; ~i; i=edge[i].next) {
v = edge[i].v;
if(v == p && (!r)) continue;
// if(v == p) continue;
if(!dfn[v]) {
tarjan(v, u, edge[i].r);
low[u] = min(low[u], low[v]);
if(low[v] > dfn[u]) edge[i].cut = edge[i^].cut = ;
}
else if(instk[v]) low[u] = min(low[u], dfn[v]);
}
if(dfn[u] == low[u]) {
bcnt++;
do {
v = stk[top--];
instk[v] = ;
belong[v] = bcnt;
} while(v != u);
}
} void dfs(int u) {
Rep(i, G[u].size()) {
int v = G[u][i];
if(dfn[v] != -) continue;
dfn[v] = max(dfn[v], dfn[u] + );
dfs(v);
}
} inline bool scan_d(int &num) {
char in;bool IsN=false;
in=getchar();
if(in==EOF) return false;
while(in!='-'&&(in<''||in>'')) in=getchar();
if(in=='-'){ IsN=true;num=;}
else num=in-'';
while(in=getchar(),in>=''&&in<=''){
num*=,num+=in-'';
}
if(IsN) num=-num;
return true;
} int main() {
// FRead();
int u, v;
while(~scan_d(n) && ~scan_d(m) && n + m) {
init();
Rep(i, n+) G[i].cl();
Rep(i, m) {
scan_d(u); scan_d(v);
if(u == v) continue;
if(u > v) swap(u, v);
tmp[i] = Tmp(u, v);
}
sort(tmp, tmp+m, cmp);
// m = unique(tmp, tmp+m) - tmp;
Rep(i, m) {
u = tmp[i].u; v = tmp[i].v;
if(i == || (tmp[i].u != tmp[i-].u || tmp[i].v != tmp[i-].v)) {
if(i < m - && (tmp[i].u == tmp[i+].u && tmp[i].v == tmp[i+].v)) {
adde(u, v, ); adde(v, u, );
}
else {
adde(u, v, ); adde(v, u, );
}
}
}
tarjan(, , );
For(u, , n+) {
for(int i = head[u]; ~i; i=edge[i].next) {
if(edge[i].cut) {
v = edge[i].v;
G[belong[u]].pb(belong[v]);
}
}
}
Clr(dfn, -); dfn[] = ;
dfs();
int pos = ;
For(i, , bcnt+) if(dfn[i] > dfn[pos]) pos = i;
Clr(dfn, -); dfn[pos] = ;
dfs(pos);
int ret = ;
Rep(i, bcnt+) {
ret = max(ret, dfn[i]);
}
printf("%d\n", bcnt - ret - );
}
RT ;
}

[HDOJ4612]Warm up(双连通分量,缩点,树直径)的更多相关文章

  1. HDU 4612 Warm up (边双连通分量+缩点+树的直径)

    <题目链接> 题目大意:给出一个连通图,问你在这个连通图上加一条边,使该连通图的桥的数量最小,输出最少的桥的数量. 解题分析: 首先,通过Tarjan缩点,将该图缩成一颗树,树上的每个节点 ...

  2. hdu4612 Warm up[边双连通分量缩点+树的直径]

    给你一个连通图,你可以任意加一条边,最小化桥的数目. 添加一条边,发现在边双内是不会减少桥的.只有在边双与边双之间加边才有效.于是,跑一遍边双并缩点,然后就变成一棵树,这样要加一条非树边,路径上的点( ...

  3. Gym - 100676H H. Capital City (边双连通分量缩点+树的直径)

    https://vjudge.net/problem/Gym-100676H 题意: 给出一个n个城市,城市之间有距离为w的边,现在要选一个中心城市,使得该城市到其余城市的最大距离最短.如果有一些城市 ...

  4. hdu 4612 Warm up 双连通缩点+树的直径

    首先双连通缩点建立新图(顺带求原图的总的桥数,事实上因为原图是一个强连通图,所以桥就等于缩点后的边) 此时得到的图类似树结构,对于新图求一次直径,也就是最长链. 我们新建的边就一定是连接这条最长链的首 ...

  5. 【HDOJ4612】【双连通分量缩点+找树的直径】

    http://acm.hdu.edu.cn/showproblem.php?pid=4612 Warm up Time Limit: 10000/5000 MS (Java/Others)    Me ...

  6. POJ3177 Redundant Paths(边双连通分量+缩点)

    题目大概是给一个无向连通图,问最少加几条边,使图的任意两点都至少有两条边不重复路径. 如果一个图是边双连通图,即不存在割边,那么任何两个点都满足至少有两条边不重复路径,因为假设有重复边那这条边一定就是 ...

  7. HDU 3686 Traffic Real Time Query System(双连通分量缩点+LCA)(2010 Asia Hangzhou Regional Contest)

    Problem Description City C is really a nightmare of all drivers for its traffic jams. To solve the t ...

  8. 训练指南 UVA - 11324(双连通分量 + 缩点+ 基础DP)

    layout: post title: 训练指南 UVA - 11324(双连通分量 + 缩点+ 基础DP) author: "luowentaoaa" catalog: true ...

  9. HDU-4612 Warm up 边双连通分量+缩点+最长链

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4612 简单图论题,先求图的边双连通分量,注意,此题有重边(admin还逗比的说没有重边),在用targ ...

  10. POJ3694 Network(边双连通分量+缩点+LCA)

    题目大概是给一张图,动态加边动态求割边数. 本想着求出边双连通分量后缩点,然后构成的树用树链剖分+线段树去维护路径上的边数和..好像好难写.. 看了别人的解法,这题有更简单的算法: 在任意两点添边,那 ...

随机推荐

  1. NP完全问题

    1.概念 好算法:Edmonds与1975年提出:具有多项式时间(O(nk)的算法为好算法. P类问题:存在多项式时间算法的问题.如:货郎问题.调度问题.最大团问题.最大独立集问题.Steiner树问 ...

  2. 树形动规--没有上司的舞会--C++

    题目来源:code[VS] 题目描述 Description Ural大学有N个职员,编号为1~N.他们有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.每个职员有一个 ...

  3. ORACLE EXPDP命令使用详细【转】

    本文转自:http://blog.csdn.net/zftang/article/details/6387325 ORACLE EXPDP命令使用详细 相关参数以及导出示例: 1. DIRECTORY ...

  4. POJ 1680 Fork() Makes Trouble

    原题链接:http://poj.org/problem?id=1680 对这道题,我只能说:我不知道题目是什么意思,但是AC还是没有问题的. 看来题目半天没明白fork()怎么个工作,但是看样例(根据 ...

  5. 你真的知道css三种存在样式(外联样式、内部样式、内联样式)的区别吗?

    css样式在html中有三种存在形态: 内联样式:<div style="display: none"></div> 内部样式: <style> ...

  6. java.lang.NullPointerException&com.cb.action.LoginAction.execute(LoginAction.java:48)

    今天做一个Spring和Struts的融合,通过bean注入后,程序一跑起来,就报这个错误: java.lang.NullPointerException com.cb.action.LoginAct ...

  7. 找不到对应的webservice配置参数[ProcessService]

    在UI端 保存时 界面显示无法保存 且报此错误 “找不到对应的webservice配置参数[ProcessService]” 此下为解决方法: 首先 在[应用管理平台]--[参数模板设置] 找到你的参 ...

  8. 深入浅出ES6(七):箭头函数 Arrow Functions

    作者 Jason Orendorff  github主页  https://github.com/jorendorff 箭头符号在JavaScript诞生时就已经存在,当初第一个JavaScript教 ...

  9. Jmeter 快速入门教程(二)--创建简单web测试

    [版权所有: whoistester.com & jmeter.cf] http://wenku.baidu.com/linkurl=9zc4VHe6vUUeMdDZPpNsRehkazZFw ...

  10. lintcode :Valid Palindrome 有效回文串

    题目: 有效回文串 给定一个字符串,判断其是否为一个回文串.只包含字母和数字,忽略大小写. 样例 "A man, a plan, a canal: Panama" 是一个回文. & ...