[双连通分量] 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 ...
随机推荐
- C++之路进阶——codevs1281(Xn数列)
1281 Xn数列 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 大师 Master 题目描述 Description 给你6个数,m, a, c, x0, n, ...
- Pandas将中文数据集转换为数值类别型数据集
一个机器学习竞赛中,题目大意如下,本文主要记录数据处理过程,为了模型训练,第一步需要将中文数据集处理为数值类别数据集保存. 基于大数据的运营商投诉与故障关联分析 目标:原始数据集是含大量中文的xls格 ...
- C#计算器代码
在刚刚接触c#的时候,就想做一个简单加减乘除计算器.这就是目标,可惜一直没有动手去做,今天特意把它简单做了.很简单,很简单,了却一个心愿了. 代码: using System; using Syste ...
- python核心编程学习记录之条件和循环
- Abot爬虫和visjs
1. 引言 最近接触Abot爬虫也有几天时间了,闲来无事打算从IMDB网站上爬取一些电影数据玩玩.正好美国队长3正在热映,打算爬取漫威近几年的电影并用vis这个JS库呈现下漫威宇宙的相关电影. Abo ...
- easyui DataGrid 工具类之 列属性class
public class ColumnVO { /** * 列标题文本 */ private String title; /** * 列字段名称 */ pr ...
- Android自定义View (二) 进阶
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/24300125 继续自定义View之旅,前面已经介绍过一个自定义View的基础的例 ...
- filebeat安装与基础用法
来自官网,版本为1.2 下载rpm包并安装 wget -c https://download.elastic.co/beats/filebeat/filebeat-1.2.3-x86_64.rpm r ...
- (转)建站知识:域名/ 空间/ IP/ 端口之间的关系
先说域名解析吧,比如说你的域名是 www.sunnymould.com,这个域名对应着一个IP地址,域名解析就是把上面的域名转换成这个IP地址的过程,这样你就可以域名访问了上面地址上的内容了. 端口映 ...
- ArcGIS Javascript查询数据库并添加到地图上
将数据存放到数据库中,动态的调取比较灵活,数据变动后不需要改变图层的属性表. 此处采用的方法是通过jquery查询数据库,并将数据库的结果生产json串返回给js,在js中动态解析json串增加点至地 ...