[双连通分量] 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# 中get和post的方法
用GET发送数据则用REQUEST.QUERYSTRING[''ID'']接收 一.request.aspx 二.request.aspx.cs 三运行效果: 以下是数据发送的途径http://loc ...
- sklearn 组合分类器
组合分类器: 组合分类器有4种方法: (1)通过处理训练数据集.如baging boosting (2)通过处理输入特征.如 Random forest (3)通过处理类标号.error_corre ...
- curl提交数据时中文乱码
1.使用curl提交数据时中文乱码解决: <?php $testJSON=array('name'=>'中文字符串','value'=>'test'); foreach ( $tes ...
- js setInterval
var monitorInterval = null; //检索cs 是否处理完成 开始: monitorInterval = setInterval(function () { CheckCS ...
- 在win 7 vs2013下 web 调试 出现“ iis Express Worker Process 已停止工作”错误
在win 7 vs2013下 web 调试 出现“ iis Express Worker Process 已停止工作”错误: 如下图: 最终解决方案如下: 用管理员身份运行CMD,输入netsh ...
- SSH 无密码远程执行脚本
ssh无密码登录及远程执行脚本要使用公钥与私钥.linux下可以用用ssh-keygen生成公钥/私钥对,下面我以CentOS7为例. 测试环境:机器A(10.0.224.80):机器B(192.16 ...
- python发送邮件方法
1.普通文本邮件 #!/usr/bin/env python # -*- coding:utf-8 -*- import smtplib from email.mime.text import MIM ...
- 结合Apache和Tomcat实现集群和负载均衡 JK 方式
本文基本参考自 轻松实现Apache,Tomcat集群和负载均衡,经由实操经历记录而成,碰到些出入,以及个别地方依据个人的习惯,所以在一定程度上未能保持原文的完整性,还望原著者海涵. 因原文中有较多的 ...
- Entity Framework 第八篇 结构优化
在之前的文章里,业务层直接调用一个包装的仓储类入口,忽略了DAL层,在业务层绕过DAL直接调用仓储类似乎也没什么大的问题,但是这样做有一个很大的弊端,就是无法做到DAL层的原子操作的复用.假如多个业务 ...
- NSISの堆栈操作
一 .堆栈 堆栈是 NSIS 维护的一堆数据,你可以根据需要往堆栈中存入任意大小的数据(as big as you like),所以你可以向堆栈中推入或读取数据,堆栈只有一个,堆栈遵守 LIFO (后 ...