求双连通图,需要使用缩点,缩点的意思就是将图中的环都缩为一个点,给这些点进行编号,最终必然形成一个树。

那么很容易推论出,至少要加的边数num=(leaf+1)/2;

leaf即:所有度为1的点的个数(度大于1的点必为根节点)

代码如下:

package com.Vjudge;


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

import static java.lang.Integer.parseInt;

//Redundant Paths
public class M_poj3177 {

static int N, M, head[], low[], dfn[], rtn[], vis[], cnt = 0, num = 0, til = 0, index = 0, MAXN = 5010, MAXM = 20020;
static StringTokenizer st;
static Edge[] edges;

public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
st = new StringTokenizer(br.readLine());
N = parseInt(st.nextToken());
M = parseInt(st.nextToken());
head = new int[MAXM];
low = new int[MAXN];
dfn = new int[MAXN];
rtn = new int[MAXN];
vis = new int[MAXN];
Arrays.fill(head, -1);
edges = new Edge[MAXM];
for (int i = 0; i < M; i++) {
st = new StringTokenizer(br.readLine());
int x = parseInt(st.nextToken());
int y = parseInt(st.nextToken());
addEdge(x, y);
addEdge(y, x);
}

for (int i = 1; i <= N; i++) {
if (dfn[i] == 0) tarjan(i);
}

for (int i = 1; i <= N; i++) {
for (int j = head[i]; j != -1; j = edges[j].next) {
int v = edges[j].to;
if (low[v] != low[i]) {
//如果把所有的桥边删掉,剩下的可以化成一个个点
//只有被桥边分开的联通分量low值不同,看作两个不同的点
//但这本身又有一条边,于是这是桥边,两个联通分量的度加一
//应该是遍历时 另一个点也会遍历到这条边,所以每次自己加一就够了
rtn[low[v]]++;
}
}
}
for (int i = 1; i <= N; i++) {
if (rtn[i] == 1) {
til++;//如果有度为1的,记录下来,给他们每个连一条边,就成了双联通
}
}
System.out.println((til + 1) / 2);
}

private static void tarjan(int u) {
dfn[u] = low[u] = ++num;
for (int i = head[u]; i != -1; i = edges[i].next) {
int v = edges[i].to;
if (vis[i] != 0) continue;
vis[i] = vis[i ^ 1] = 1;
if (dfn[v] == 0) {
tarjan(v);
low[u] = Math.min(low[u], low[v]);
} else {
low[u] = Math.min(low[u], dfn[v]);
}
}
}

private static void addEdge(int from, int to) {
if ((head[from] != -1) && edges[head[from]].to == to) {
return;
}
edges[cnt] = new Edge(to, head[from]);
head[from] = cnt++;
}

static class Edge {
int to;
int next;

public Edge(int to, int next) {
this.to = to;
this.next = next;
}
}
}

 

posted on 2020-10-22 09:07  BryantKun  阅读(103)  评论(0)    收藏  举报