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

Warm up

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)
Total Submission(s): 7206    Accepted Submission(s): 1681

Problem Description
  N planets are connected by M bidirectional channels that allow instant transportation. It's always possible to travel between any two planets through these channels.
  If we can isolate some planets from others by breaking only one channel , the channel is called a bridge of the transportation system.
People don't like to be isolated. So they ask what's the minimal number of bridges they can have if they decide to build a new channel.
  Note that there could be more than one channel between two planets.
 
Input
  The input contains multiple cases.
  Each case starts with two positive integers N and M , indicating the number of planets and the number of channels.
  (2<=N<=200000, 1<=M<=1000000)
  Next M lines each contains two positive integers A and B, indicating a channel between planet A and B in the system. Planets are numbered by 1..N.
  A line with two integers '0' terminates the input.
 
Output
  For each case, output the minimal number of bridges after building a new channel in a line.
 
Sample Input
4 4
1 2
1 3
1 4
2 3
0 0
 
Sample Output
0
 
Author
SYSU
 
Source
 
Recommend
zhuyuanchen520
 
 
题解:
1.用Tarjan算法求出每个边双联通分量,由于每一对点之间可以有多条边,所以在判断边是否被重复访问时,需要依据边的下标而定 。
2.对每个边双联通分量进行缩点,缩点之后得到的是一棵无根树。
3.在树上添加一条边,使得桥的数目减少最多。最多能减少多少呢?树上最长路。
 
 
vector建树:
 #include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <string>
#include <set>
using namespace std;
typedef long long LL;
const double EPS = 1e-;
const int INF = 2e9;
const LL LNF = 2e18;
const int MAXN = 2e5+; struct Edge
{
int to, next;
}edge[MAXN*];
int tot, head[MAXN];
vector<int>g[MAXN]; void addedge(int u, int v)
{
edge[tot].to = v;
edge[tot].next = head[u];
head[u] = tot++;
} int index, dfn[MAXN], low[MAXN];
int top, Stack[MAXN], instack[MAXN];
int block, belong[MAXN]; void Tarjan(int u, int pre)
{
dfn[u] = low[u] = ++index;
Stack[top++] = u;
instack[u] = true;
for(int i = head[u]; i!=-; i = edge[i].next)
{
//因为一对点之间可能有多条边,所以不能根据v是否为上一个点来防止边是否被重复访问。而需要根据边的编号
if((i^)==pre) continue;
int v = edge[i].to;
if(!dfn[v])
{
Tarjan(v, i);
low[u] = min(low[u], low[v]);
}
else if(instack[v])
low[u] = min(low[u], dfn[v]);
} if(low[u]==dfn[u])
{
block++;
int v;
do
{
v = Stack[--top];
instack[v] = false;
belong[v] = block;
}while(v!=u);
}
} int diameter, endpoint;
int dfs(int u, int pre, int dep)
{
if(dep>diameter) { endpoint = u; diameter = dep; }
for(int i = ; i<g[u].size(); i++)
if(g[u][i]!=pre)
dfs(g[u][i], u, dep+);
} void init(int n)
{
tot = ;
memset(head, -, sizeof(head)); index = ;
memset(dfn, , sizeof(dfn));
memset(low, , sizeof(low)); top = ;
memset(instack, false, sizeof(instack)); block = ;
for(int i = ; i<=n; i++)
belong[i] = i, g[i].clear();
} int main()
{
int n, m;
while(scanf("%d%d", &n, &m) && (n||m) )
{
init(n);
for(int i = ; i<=m; i++)
{
int u, v;
scanf("%d%d", &u, &v);
addedge(u, v);
addedge(v, u);
} Tarjan(, -);
for(int u = ; u<=n; u++)
for(int i = head[u]; i!=-; i = edge[i].next)
{
int v = edge[i].to;
if(belong[u]!=belong[v])
g[belong[u]].push_back(belong[v]);
} endpoint = , diameter = ;
dfs(, -, );
dfs(endpoint, -, );
printf("%d\n", block--diameter);
}
}
前向星建树:
 #include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <string>
#include <set>
using namespace std;
typedef long long LL;
const double EPS = 1e-;
const int INF = 2e9;
const LL LNF = 2e18;
const int MAXN = 2e5+; struct Edge
{
int from, to, next;
}edge[MAXN*];
int tot, head[MAXN]; void addedge(int u, int v)
{
edge[tot].from = u;
edge[tot].to = v;
edge[tot].next = head[u];
head[u] = tot++;
} int index, dfn[MAXN], low[MAXN];
int top, Stack[MAXN], instack[MAXN];
int block, belong[MAXN]; void Tarjan(int u, int pre)
{
dfn[u] = low[u] = ++index;
Stack[top++] = u;
instack[u] = true;
for(int i = head[u]; i!=-; i = edge[i].next)
{
//因为一对点之间可能有多条边,所以不能根据v是否为上一个点来防止边是否被重复访问。而需要根据边的编号
if((i^)==pre) continue;
int v = edge[i].to;
if(!dfn[v])
{
Tarjan(v, i);
low[u] = min(low[u], low[v]);
}
else if(instack[v])
low[u] = min(low[u], dfn[v]);
} if(low[u]==dfn[u])
{
block++;
int v;
do
{
v = Stack[--top];
instack[v] = false;
belong[v] = block;
}while(v!=u);
}
} int diameter, endpoint;
int dfs(int u, int pre, int dep)
{
if(dep>diameter) { endpoint = u; diameter = dep; }
for(int i = head[u]; i!=-; i = edge[i].next)
if(edge[i].to!=pre)
dfs(edge[i].to, u, dep+);
} void init(int n)
{
tot = ;
memset(head, -, sizeof(head)); index = ;
memset(dfn, , sizeof(dfn));
memset(low, , sizeof(low)); top = ;
memset(instack, false, sizeof(instack)); block = ;
for(int i = ; i<=n; i++)
belong[i] = i;
} int main()
{
int n, m;
while(scanf("%d%d", &n, &m) && (n||m) )
{
init(n);
for(int i = ; i<=m; i++)
{
int u, v;
scanf("%d%d", &u, &v);
addedge(u, v);
addedge(v, u);
} Tarjan(, -);
tot = ;
memset(head, -, sizeof(head));
for(int i = ; i<*m; i++)
{
int u = edge[i].from, v = edge[i].to;
if(belong[u]!=belong[v])
addedge(belong[u], belong[v]);
} endpoint = , diameter = ;
dfs(, -, );
dfs(endpoint, -, );
printf("%d\n", block--diameter);
}
}
 

HDU4612 Warm up —— 边双联通分量 + 重边 + 缩点 + 树上最长路的更多相关文章

  1. POJ-3352-RoadConstruction(边双联通分量,缩点)

    链接:https://vjudge.net/problem/POJ-3352#author=0 题意: 给一个无向连通图,至少添加几条边使得去掉图中任意一条边不改变图的连通性(即使得它变为边双连通图) ...

  2. HDU4738 Caocao's Bridges —— 边双联通分量 + 重边

    题目链接:https://vjudge.net/problem/HDU-4738 A network administrator manages a large network. The networ ...

  3. [J]computer network tarjan边双联通分量+树的直径

    https://odzkskevi.qnssl.com/b660f16d70db1969261cd8b11235ec99?v=1537580031 [2012-2013 ACM Central Reg ...

  4. 【UVA10972】RevolC FaeLoN (求边双联通分量)

    题意: 给你一个无向图,要求把所有无向边改成有向边,并且添加最少的有向边,使得新的有向图强联通. 分析: 这题的解法还是很好想的.先用边双联通分量缩点,然后找新图中入度为0和为1的点,入度为0则ans ...

  5. ARC062 - F. Painting Graphs with AtCoDeer (Polya+点双联通分量)

    似乎好久都没写博客了....赶快来补一篇 题意 给你一个 \(n\) 个点 , 没有重边和自环的图 . 有 \(m\) 条边 , 每条边可以染 \(1 \to k\) 中的一种颜色 . 对于任意一个简 ...

  6. POJ2942 Knights of the Round Table【Tarjan点双联通分量】【二分图染色】【补图】

    LINK 题目大意 有一群人,其中有一些人之间有矛盾,现在要求选出一些人形成一个环,这个环要满足如下条件: 1.人数大于1 2.总人数是奇数 3.有矛盾的人不能相邻 问有多少人不能和任何人形成任何的环 ...

  7. lightoj 1300 边双联通分量+交叉染色求奇圈

    题目链接:http://lightoj.com/volume_showproblem.php?problem=1300 边双连通分量首先dfs找出桥并标记,然后dfs交叉着色找奇圈上的点.这题只要求在 ...

  8. HDU5409---CRB and Graph 2015多校 双联通分量缩点

    题意:一个联通的无向图, 对于每一条边, 若删除该边后存在两点不可达,则输出这两个点, 如果存在多个则输出第一个点尽可能大,第二个点尽可能小的. 不存在输出0 0 首先 若删除某一条边后存在多个联通分 ...

  9. poj2942(双联通分量,交叉染色判二分图)

    题意:一些骑士,他们有些人之间有矛盾,现在要求选出一些骑士围成一圈,圈要满足如下条件:1.人数大于1.2.总人数为奇数.3.有仇恨的骑士不能挨着坐.问有几个骑士不能和任何人形成任何的圆圈. 思路:首先 ...

随机推荐

  1. mysql 常用命令(一)

    1. 函数向日期添加指定的时间间隔 DATE_ADD(date,INTERVAL expr type)eg:DATE_ADD(CURDATE(),INTERVAL 1 MONTH) //在当前时间加一 ...

  2. HDU 2462 The Luckiest number

    The Luckiest number Time Limit: 1000ms Memory Limit: 32768KB This problem will be judged on HDU. Ori ...

  3. Leetcode 307.区域检索-数组可修改

    区域检索-数组可修改 给定一个整数数组  nums,求出数组从索引 i 到 j  (i ≤ j) 范围内元素的总和,包含 i,  j 两点. update(i, val) 函数可以通过将下标为 i 的 ...

  4. php 时间 数组替换

    //随机数和时间//随机数生产器//echo rand();//echo "<br>";//生成某个范围的随机数//echo rand(0,10);//echo &qu ...

  5. HDU 1426 dancing links解决数独问题

    题目大意: 这是一个最简单的数独填充题目,题目保证只能产生一种数独,所以这里的初始9宫格较为稠密,可以直接dfs也没有问题 但最近练习dancing links,这类数据结构解决数独无疑效率会高很多 ...

  6. Django 的信号 & Flask 的信号

    信号:框架内部已帮助开发者预留的可扩展的位置 一.Django 的信号 项目目录结构: django_signal |--- app01 |--- models.py |--- views.py .. ...

  7. MYSQL常见运算符和函数【重要】

    字符函数 (1)CONCAT():字符连接 SELECT CONCAT(‘IMOOC’,’-‘,’MySQL’);//IMOOC-MySQL SELECT CONCAT (first_name,las ...

  8. linux命令1——基础

    Rm 删除命令 Rm [选项][文件] 删除一个文件或者目录 选项:r 递归的删除文件夹及其子文件,f 忽略不存在的文件(不提示) (2)rm删除目录下所有文件,但不删除目录 >>rm - ...

  9. hdu1875kruskal简单应用。

    标记是dificulty 2,水,开始kruskal时练手题,只需开始时数据处理下,不符合要求的边不要,要理解并查集和Kruskal,就简单了,判断下是否联通图,(只需在记加入有效边时候统计连通分支数 ...

  10. $.post()用法例子

    1:删除用户操作 $('.delete').click(function(){ var classid=$(this).parent().siblings().eq(0).children().val ...