[双连通分量] POJ 3694 Network
Time Limit: 5000MS | Memory Limit: 65536K | |
Total Submissions: 9434 | Accepted: 3511 |
Description
A network administrator manages a large network. The network consists of N computers and M links between pairs of computers. Any pair of computers are connected directly or indirectly by successive links, so data can be transformed between any two computers. The administrator finds that some links are vital to the network, because failure of any one of them can cause that data can't be transformed between some computers. He call such a link a bridge. He is planning to add some new links one by one to eliminate all bridges.
You are to help the administrator by reporting the number of bridges in the network after each new link is added.
Input
The input consists of multiple test cases. Each test case starts with a line containing two integers N(1 ≤ N ≤ 100,000) and M(N - 1 ≤ M ≤ 200,000).
Each of the following M lines contains two integers A and B ( 1≤ A ≠ B ≤ N), which indicates a link between computer A and B. Computers are numbered from 1 to N. It is guaranteed that any two computers are connected in the initial network.
The next line contains a single integer Q ( 1 ≤ Q ≤ 1,000), which is the number of new links the administrator plans to add to the network one by one.
The i-th line of the following Q lines contains two integer A and B (1 ≤ A ≠ B ≤ N), which is the i-th added new link connecting computer A and B.
The last test case is followed by a line containing two zeros.
Output
For each test case, print a line containing the test case number( beginning with 1) and Q lines, the i-th of which contains a integer indicating the number of bridges in the network after the first i new links are added. Print a blank line after the output for each test case.
Sample Input
3 2
1 2
2 3
2
1 2
1 3
4 4
1 2
2 1
2 3
1 4
2
1 2
3 4
0 0
Sample Output
Case 1:
1
0 Case 2:
2
0
Source
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
struct list
{
int v;
list *next;
};
list *head[110010],*rear[110010];
int father[110010],times,dfn[110010],low[110010],bridge[110010],bridgenum,n;
int dep[110010];
void init()
{
int i;
memset(head,0,sizeof(head));
memset(dep,0,sizeof(dep));
memset(rear,0,sizeof(rear));
for(i=1;i<=n;++i) father[i]=i;
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(bridge,0,sizeof(bridge));
times=bridgenum=0;
}
void insert(int a,int b)
{
if(rear[a]!=NULL)
{
rear[a]->next=new list;
rear[a]=rear[a]->next;
} else head[a]=rear[a]=new list;
rear[a]->v=b;
rear[a]->next=NULL;
return;
}
void tarjian(int v)
{
bool flag=true;
dfn[v]=low[v]=++times;
dep[v]=dep[father[v]]+1;
for(list *p=head[v];p!=NULL;p=p->next)
{
if(p->v==father[v]&&flag)
{
flag=false;
continue;
}
if(!dfn[p->v])
{
father[p->v]=v;
tarjian(p->v);
low[v]=min(low[v],low[p->v]);
if(low[p->v]>dfn[v])
{
++bridgenum;
bridge[p->v]=1;
}
}else low[v]=min(low[v],dfn[p->v]);
}
}
void lca(int a,int b)
{
if(dep[a]<dep[b]) swap(a,b);
while(dep[a]!=dep[b])
{
if(bridge[a])
{
bridge[a]=0;
--bridgenum;
}
a=father[a];
}
while(a!=b)
{
if(bridge[a])
{
bridge[a]=0;
--bridgenum;
}
if(bridge[b])
{
bridge[b]=0;
--bridgenum;
}
a=father[a];
b=father[b];
}
return;
}
int main()
{
int m,i,a,b,q,ccase=0;
while(~scanf("%d%d",&n,&m),n&&m)
{
init();
for(i=0;i<m;++i)
{
scanf("%d%d",&a,&b);
insert(a,b);insert(b,a);
}
tarjian(1);
scanf("%d",&q);
printf("Case %d:\n",++ccase);
for(i=1;i<=q;++i)
{
scanf("%d%d",&a,&b);
lca(a,b);
printf("%d\n",bridgenum);
}
}
return 0;
}
解题思路2:在原来的基础上用并查集优化,这种做法是看了大神们的解题思路写出的。
将双连通的两个点弄成一个集合,这样在LCA时只要判断是否是一个集合,将桥的数量减去即可。
#include<stdio.h>
#include<string.h>
struct list
{
int v;
list *next;
};
list *head[111010],*rear[111010];
int n,m,father[111010],dep[110010],low[110010],fath[110010],bridgenum;
void init()
{
int i;
memset(head,0,sizeof(head));
memset(rear,0,sizeof(rear));
memset(dep,0,sizeof(dep));
memset(low,0,sizeof(low));
memset(fath,0,sizeof(fath));
for(i=1;i<=n;++i) father[i]=i;
bridgenum=0;
}
void insert(int a,int b)
{
if(rear[a]!=NULL)
{
rear[a]->next=new list;
rear[a]=rear[a]->next;
} else head[a]=rear[a]=new list;
rear[a]->v=b;
rear[a]->next=NULL;
}
int find(int x)
{
return father[x]==x?x:father[x]=find(father[x]);
}
void merge(int x,int y)
{
int fx=find(x);
int fy=find(y);
if(fx!=fy) father[fx]=fy;
}
void tarjian(int v,int deps)
{
bool flag=true;
dep[v]=low[v]=deps;
for(list *p=head[v];p!=NULL;p=p->next)
{
if(p->v==fath[v]&&flag)
{
flag=false;
continue;
}
if(!dep[p->v])
{
fath[p->v]=v;
tarjian(p->v,deps+1);
if(low[v]>low[p->v]) low[v]=low[p->v];
if(low[p->v]<=dep[v]) merge(p->v,v);
else bridgenum++;
}
else if(low[v]>dep[p->v]) low[v]=dep[p->v];
}
}
void judge(int v)
{
int x=find(v);
int y=find(fath[v]);
if(x!=y)
{
--bridgenum;
father[x]=y;
}
}
void lca(int u,int v)
{
while(dep[u]>dep[v])
{
judge(u);
u=fath[u];
}
while(dep[u]<dep[v])
{
judge(v);
v=fath[v];
}
while(u!=v)
{
judge(u);judge(v);
u=fath[u];v=fath[v];
}
}
int main()
{
int a,b,q,num=0;
while(~scanf("%d%d",&n,&m))
{
if(n==0&&m==0) break;
init();
while(m--)
{
scanf("%d%d",&a,&b);
insert(a,b);insert(b,a);
}
printf("Case %d:\n",++num);
tarjian(1,1);
scanf("%d",&q);
while(q--)
{
scanf("%d%d",&a,&b);
if(find(a)!=find(b)) lca(a,b);
printf("%d\n",bridgenum);
}
printf("\n");
}
return 0;
}
[双连通分量] POJ 3694 Network的更多相关文章
- Poj 3694 Network (连通图缩点+LCA+并查集)
题目链接: Poj 3694 Network 题目描述: 给出一个无向连通图,加入一系列边指定的后,问还剩下多少个桥? 解题思路: 先求出图的双连通分支,然后缩点重新建图,加入一个指定的边后,求出这条 ...
- poj 3694 Network 边双连通+LCA
题目链接:http://poj.org/problem?id=3694 题意:n个点,m条边,给你一个连通图,然后有Q次操作,每次加入一条边(A,B),加入边后,问当前还有多少桥,输出桥的个数. 解题 ...
- poj 3694 Network(割边+lca)
题目链接:http://poj.org/problem?id=3694 题意:一个无向图中本来有若干条桥,有Q个操作,每次加一条边(u,v),每次操作后输出桥的数目. 分析:通常的做法是:先求出该无向 ...
- POJ 3694——Network——————【连通图,LCA求桥】
Network Time Limit:5000MS Memory Limit:65536KB 64bit IO Format:%I64d & %I64u Submit Stat ...
- [双连通分量] POJ 3177 Redundant Paths
Redundant Paths Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 13712 Accepted: 5821 ...
- poj 3694 Network(双连通分量)
题目:http://poj.org/problem?id=3694 #include <iostream> #include <cstring> #include <cs ...
- POJ 3694 Network 无向图双联通+LCA
一开始题目没看清楚,以为是增加那条边后还有多少桥,所以就当做是无向图tarjan缩点后建树,然后求u,v的最近公共祖先,一直wa. 后来再看题目后才发现边放上去后不会拿下来了,即增加i条边后桥的数量. ...
- POJ 3694 Network (tarjan + LCA)
题目链接:http://poj.org/problem?id=3694 题意是给你一个无向图n个点,m条边,将m条边连接起来之后形成一个图,有Q个询问,问将u和v连接起来后图中还有多少个桥. 首先用t ...
- poj 3694 Network : o(n) tarjan + O(n) lca + O(m) 维护 总复杂度 O(m*q)
/** problem: http://poj.org/problem?id=3694 问每加一条边后剩下多少桥 因为是无向图,所以使用tarjan缩点后会成一棵树并维护pre数组 在树上连一条边(a ...
随机推荐
- Java关于md5+salt盐加密验证
一.陈述一下工作流程: 1.根据已有的密码字符串去生成一个密码+盐字符串,可以将盐的加密字符串也存放在数据库(看需求), 2.验证时将提交的密码字符串进行同样的加密再从数据库中取得已有的盐进行组合密码 ...
- css3创建一个上下线性渐变色背景的div
<!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <title> ...
- PAT乙级 1032. 挖掘机技术哪家强(20)
1032. 挖掘机技术哪家强(20) 时间限制 200 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 CHEN, Yue 为了用事实说明挖掘机技术到底 ...
- VMWare安装Solaris虚拟机的网络设置
虚拟机的网卡使用Host-only. 在VMWare取消Host-only的DHCP. 在虚拟机的Solaris系统里ipadm命令配置ip.
- Jenkins入门系列之——01第一章 Jenkins是什么?
第一章 Jenkins是什么? Jenkins 是一个可扩展的持续集成引擎. 主要用于: l 持续.自动地构建/测试软件项目. l 监控一些定时执行的任务. Jenkins拥有的特性包括: l 易于安 ...
- C#使用DataSet Datatable更新数据库的三种实现方法
本文以实例形式讲述了使用DataSet Datatable更新数据库的三种实现方法,包括CommandBuilder 方法.DataAdapter 更新数据源以及使用sql语句更新.分享给大家供大家参 ...
- Linux 各文件夹介绍
http://www.cnblogs.com/amboyna/archive/2008/02/16/1070474.html linux下的文件结构,看看每个文件夹都是干吗用的/bin 二进制可执行命 ...
- 数据库事务的特性(ACID)
数据库的事务是数据库中一系列(增删查改)操作的集合. 一般来说,事务的范围根据业务而定,比如转账.修改个人信息 转账:从A账户将200元转移到B账户 从A账户中扣除200元 将200元加入到B账户中 ...
- CSS3的chapter2
CSS的选择符有很多,大致分为八种: 通配选择符 元素选择符 群组选择符 关系选择符 id及class类选择符 伪类选择符 属性选择符 伪对象选择符 1.通配选择符: 可以使用模糊指定的方式来对对象进 ...
- [jetbrains系列] 外链第三方库+代码补全设置
jetbrains系列的IDE真的是太好用了,有种相见恨晚的感觉. 在开发过程中第三方库是必不可少的,在开发的时候如果有一个可以补全的IDE可以节省查文档的时间. 举个例子:给pycharm配pysp ...