您的位置:首页 > 其它

POJ 3694 Network 双联通分量 + lca

2016-05-08 17:39 519 查看
题目:http://poj.org/problem?id=3694

题意:给定一个连通图,现有q个操作,每个操作连接两个点,求每次操作后图中有多少桥

思路:每次操作后用tarjan求桥肯定会T的,可以先求桥并标记,把边双连通分量缩点,缩成一棵树,然后对于每个查询,直接去找它们的lca,并把经过路径的桥去掉标记,因为路径上的桥都变成了圈的一部分,不再是桥了。不过做得时候不一定需要缩图。

总结:我的缩图写法有点搓,比不上大神的效率。。。

其一:不缩图

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;

const int N = 100100;
struct edge
{
int to, next;
} g[N*10];
int dfn
, Dfn
, low
, head
, father
;
bool bridge
;
int index, cnt, res;
int n, m;
void init()
{
memset(dfn, -1, sizeof dfn);
memset(head, -1, sizeof head);
memset(bridge, 0, sizeof bridge);
index = cnt = res = 0;
}
void add_edge(int v, int u)
{
g[cnt].to = u;
g[cnt].next = head[v];
head[v] = cnt++;
}
void tarjan(int v, int fa)
{
dfn[v] = low[v] = index++;
bool f = true;
int u;
Dfn[v] = Dfn[fa] + 1; /*Dfn数组储存的是点的深度*/
for(int i = head[v]; i != -1; i = g[i].next)
{
u = g[i].to;
if(u == fa && f) /*判重边*/
{
f = false;
continue;
}
if(dfn[u] == -1)
{
father[u] = v;
tarjan(u, v);
low[v] = min(low[v], low[u]);
if(dfn[v] < low[u])
{
res++;
bridge[u] = true;
}
}
else
low[v] = min(low[v], dfn[u]);
}
}
void lca(int v, int u) /*裸LCA*/
{
if(Dfn[v] < Dfn[u]) swap(v, u);
while(Dfn[v] > Dfn[u])
{
if(bridge[v])
res--, bridge[v] = false;
v = father[v];
}
while(v != u)
{
if(bridge[v])
res--, bridge[v] = false;
if(bridge[u])
res--, bridge[u] = false;
v = father[v], u = father[u];
}
}
int main()
{
int q, a, b, x = 0;
while(scanf("%d%d", &n, &m), n || m)
{
init();
for(int i = 0; i < m; i++)
{
scanf("%d%d", &a, &b);
add_edge(a, b);
add_edge(b, a);
}
tarjan(1, 0);
scanf("%d", &q);
printf("Case %d:\n", ++x);
while(q--)
{
scanf("%d%d", &a, &b);
lca(a, b);
printf("%d\n", res);
}
}
return 0;
}


其二:缩图加并查集优化
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;

const int N = 100100;
struct edge
{
int to, next;
} g[N*10];
int dfn
, low
, st
, dcc
, head
, deep
, fat
, par
;
bool vis
, bridge
;
int index, cnt, top, num, sum;
int a[N*2], b[N*2];
int n, m;
void init()
{
for(int i = 1; i <= n; i++) par[i] = i;
memset(dfn, -1, sizeof dfn);
memset(head, -1, sizeof head);
memset(bridge, 0, sizeof bridge);
memset(vis, 0, sizeof vis);
index = cnt = top = num = 0;
}
void add_edge(int v, int u)
{
g[cnt].to = u;
g[cnt].next = head[v];
head[v] = cnt++;
}
void tarjan(int v, int fa)
{
dfn[v] = low[v] = index++;
st[top++] = v;
vis[v] = true;
bool f = true;
int u;
for(int i = head[v]; i != -1; i = g[i].next)
{
u = g[i].to;
if(u == fa && f) /*判重边*/
{
f = false;
continue;
}
if(dfn[u] == -1)
{
tarjan(u, v);
low[v] = min(low[v], low[u]);
}
else if(vis[u])
low[v] = min(low[v], dfn[u]);
}
if(dfn[v] == low[v])
{
num++;
do
{
u = st[--top];
vis[u] = false;
dcc[u] = num;
}
while(u != v);
bridge[num] = true; /*缩点后的桥*/
}
}
void dfs(int v, int d)
{
vis[v] = true;
deep[v] = d;
int u;
for(int i = head[v]; i != -1; i = g[i].next)
if(!vis[u = g[i].to])
fat[u] = v, dfs(u, d + 1);
}
int ser(int x)
{
int r = x, i = x, j;
while(r != par[r]) r = par[r];
while(i != r) j = par[i], par[i] = r, i = j;
return r;
}
void lca(int v, int u) /*LCA*/
{
v = ser(v), u = ser(u);
if(v == u) return;

if(deep[v] < deep[u]) swap(v, u);
while(deep[v] > deep[u])
{
if(bridge[v])
num--, bridge[v] = false;
v = fat[v];
}
while(v != u)
{
if(bridge[v])
num--, bridge[v] = false;
if(bridge[u])
num--, bridge[u] = false;
v = fat[v], u = fat[u];
}
}
int main()
{
int z = 0;
while(scanf("%d%d", &n, &m), n || m)
{
init();
for(int i = 0; i < m; i++)
{
scanf("%d%d", a + i, b + i);
add_edge(a[i], b[i]);
add_edge(b[i], a[i]);
}

tarjan(1, -1);
/*重新建图,缩点建树*/
memset(head, -1, sizeof head);
cnt = 0;
for(int i = 0; i < m; i++)
if(dcc[a[i]] != dcc[b[i]])
{
add_edge(dcc[a[i]], dcc[b[i]]);
add_edge(dcc[b[i]], dcc[a[i]]);
}
memset(vis, 0, sizeof vis);
dfs(dcc[1], 1);
int q, x, y;
scanf("%d", &q);
num--; /*桥的个数为连通分量个数减1*/
printf("Case %d:\n", ++z);
while(q--)
{
scanf("%d%d", &x, &y);
lca(dcc[x], dcc[y]);
printf("%d\n", num);
}
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: