POJ 3177 Redundant Paths
这道题是求一个变双联通分量,问你,最少加多少条边,可以使任意两个节点之间可以有两条路径
首先我们要知道,通过联通分量缩点以后我们可以形成一棵树,那么树的叶子节点数为cnt, (cnt+1)/2 便是答案,
然后就是Trajan求割边了,
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
using namespace std;
#define MAXN 55555
#define MAXE 311111
struct Edge
{
int u, v, next;
} e[MAXE];
int head[MAXE], cnt;
int dfn[MAXN], low[MAXN], out[MAXN], vis[MAXN];
int bri[MAXN][2], fa[MAXN], belong[MAXN];
int blo, dep, nbri;
void init()
{
cnt = blo = dep = nbri = 0;
memset(head, -1, sizeof(head));
memset(belong, -1, sizeof(belong));
memset(fa, -1, sizeof(fa));
memset(vis, 0, sizeof(vis));
memset(out, 0, sizeof(low));
}
int findfa(int x)
{
if(fa[x] == -1) return x;
return fa[x] = findfa(fa[x]);
}
void unit(int x, int y)
{
int fax = findfa(x);
int fay = findfa(y);
if(fax != fay)
fa[fax] = fay;
}
void Addedge( int uu, int vv)
{
e[cnt].u = uu, e[cnt].v = vv, e[cnt].next = head[uu];
head[uu] = cnt++;
}
void dfs( int u, int fa)
{
vis[u] = 1;
dfn[u] = low[u] = ++ dep;
int pre_num = 0;
for( int i = head[u] ; i != -1; i = e[i].next)
{
int v = e[i].v;
if( v == fa && !pre_num)
{
pre_num = 1;
continue;
}
if(vis[v] == 0)
{
dfs(v, u);
low[u] = min(low[u], low[v]);
if(low[v] > dfn[u])
{
bri[nbri][0] = u;
bri[nbri][1] = v;
nbri++;
}
else
unit(u, v);
}
else if(vis[v] == 1)
low[u] = min(low[u], dfn[v]);
}
vis[u] = 1;
}
void solve( int n, int m)
{
for(int i = 1; i <= n; i++)
if(!dfn[i])
dfs(i, -1);
int node = 1;
for( int i = 1; i <= n; i++)
{
int k = findfa(i);
if(belong[k] == -1) belong[k] = node++;
belong[i] = belong[k];
}
int count = 0;
for( int i = 0; i < nbri; i++)
{
int u = bri[i][0], v = bri[i][1];
out[belong[u]]++;
out[belong[v]]++;
}
for( int i = 0; i < node; i++)
if(out[i] == 1) count++;
printf("%d\n",(count+1)/2);
}
int main()
{
int n, m, u, v;
while(scanf("%d %d",&n, &m) != EOF)
{
init();
for( int i = 1; i <= m; i++)
{
scanf("%d %d",&u, &v);
if( u == v) continue;
Addedge(u, v);
Addedge(v, u);
}
solve(n ,m);
}
return 0;
}