[双连通分量] 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 ...
随机推荐
- Android项目:proguard混淆第三方jar.
1.Gson混淆 ## ---------------------------------- ## ########## Gson混淆 ########## ## ------------- ...
- android cocos2d-x for Android安装和学习笔记(请用adt-bundle21.1或以上导入)
引用:http://weimingtom.iteye.com/blog/1483566 (20121108)注意:这篇文章用cdt编译ndk工程的内容已过时(现在可以用adt-bundle,避免配置繁 ...
- Java关于md5加密
package com.mi.util; /** * md5+salt 长度为32的加密 * @author admin * */ public class MD5 { public static v ...
- JS代码执行顺序
JavaScript执行引擎并非一行一行地分析和执行程序,而是一段一段地分析执行的.而且在分析执行同一段代码中,定义式的函数语句会被提取出来优先执行.函数定义执行完后,才会按顺序执行其他代码. 先看看 ...
- python对json的操作总结
Json简介:Json,全名 JavaScript Object Notation,是一种轻量级的数据交换格式.Json最广泛的应用是作为AJAX中web服务器和客户端的通讯的数据格式.现在也常用于h ...
- Java并发编程初探
package test; import java.io.File; import java.io.FileReader; import java.io.IOException; import jav ...
- 利用a标签特性解析地址(附加属性说明)
首先我们看看实例 a.href = 'http://www.cnblogs.com/wayou/p/'; console.log(a.host); 控制台会输出 "www.cnblogs.c ...
- C#对多个集合和数组的操作(合并,去重,判断)
在开发过程中.数组和集合的处理是最让我们担心.一般会用for or foreach 来处理一些操作.这里介绍一些常用的集合跟数组的操作函数. 首先举例2个集合A,B. List<int> ...
- Linux命令大全----常用文件操作命令
林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka ls 这个命令是经常用到的,用来显示当前目录下有哪些文件 ,ls最常用的参数有三个: -a - ...
- MySql + EF6 + .Net Core
2016年8月17日01:21:29 更新:这里介绍一下一个开源的 EF Core 的 MySQL 组件 [MySQL for .NET Core - Pomelo 扩展包系列][http://www ...