图的割点
来源:互联网 发布:淘宝估值 编辑:程序博客网 时间:2024/04/30 08:32
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Scanner;
public class Test {
static Vertex[] v;
// 用于记录每一个顶点的时间戳
static int[] timeMark;
// 用于记录每一个顶点能达到的最小时间戳
static int[] lowTimeMark;
static int root;
// 用于标记当前顶点的时间戳
static int index = 0;
// 用于记录这一个顶点是否为割点
static boolean[] flag;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
v = new Vertex[n];
timeMark = new int[n];
lowTimeMark = new int[n];
flag = new boolean[n];
int m = scanner.nextInt();
for (int i = 0; i < n; i++) {
v[i] = new Vertex();
v[i].setId(i);
flag[i] = false;
}
Edge edge = null;
int temp1 = 0;
int temp2 = 0;
for (int i = 0; i < m; i++) {
temp1 = scanner.nextInt();
temp2 = scanner.nextInt();
edge = new Edge(temp1, temp2, 0);
v[temp1].getEdges().add(0, edge);
edge = new Edge(temp2, temp1, 0);
v[temp2].getEdges().add(0, edge);
}
// 假定树根为第一个点
root = 0;
// 从第一个点开始遍历,寻找割点
findCutPoint(0, root);
System.out.println(Arrays.toString(flag));
scanner.close();
}
private static void findCutPoint(int curennt, int father) {
Vertex vertex = v[curennt];
int child = 0;
index++;
timeMark[curennt] = index;
lowTimeMark[curennt] = index;
LinkedList<Edge> edges = vertex.getEdges();
for (int i = 0; i < edges.size(); i++) {
// 表明这个点还没有被初始化过还没有更新过时间戳
if (timeMark[edges.get(i).getEnd()] == 0) {
child++;
findCutPoint(edges.get(i).getEnd(), curennt);
// 充分利用刚刚从孩子那里更新到的,最小戳的数据,来更新自己的最小戳数据,然后再将其作用到上一层
lowTimeMark[curennt] = lowTimeMark[curennt] > lowTimeMark[edges
.get(i).getEnd()] ? lowTimeMark[edges.get(i).getEnd()]
: lowTimeMark[curennt];
// 如果孩子能回到的最小时间戳大于或者等于自身时间戳的话,表明自己就是割点了,因为孩子在不经过自己的情况下
// 无法返回到更早时间戳的点了
if (curennt != root
&& timeMark[curennt] <= lowTimeMark[edges.get(i)
.getEnd()]) {
flag[curennt] = true;
}
// 注意这里了!!!!顶点的孩子数会存在一个坑!!!!,一个特别制约的数字,就是2和比2大的数值
// 为什么是2了?你想一下嘛,如果比2小的话,那只能是1了,1的话,如果没有了这个顶点,最多是这个点没了
// 其他都没什么,因为他只有一个孩子嘛,他没了,那他唯一的孩子就做根节点咯。
// 如果比2大的话呢,其实原理跟情况是2时,是一样的,只不过这里在2的时候,就将其置为割点了,后面比2大的时候
// 就没必要在将其置为割点了。
// 好吧,那下面说一下2是怎么来的吧,关键是注意timeMark[edges.get(i).getEnd()] ==
// 0,这个条件吧,
// 表示还没有初始化,而有什么点会没初始化呢?就两种情况:要么是第一轮遍历时被访问到的点,因为是第一次访问,所以肯定是
// 没有初始化的。要么还有一种情况,就是这个点只与割点有联系,与其他点没有联系,所以在其他点遍历时,无法
// 遍历到它,也就无法对其进行初始化操作了。
if (curennt == root && child == 2) {
flag[curennt] = true;
}
} else {
// 表明这个点已经被初始化过了。因此这里将会作为遍历父节点,寻找能回到最小时间戳的终点。
// 下面就开始,比对当前点的时间戳和这个终点的时间戳,看看能不能更新当前点的时间戳
// 而且这个更新完之后,退出这一层递归时,这一层的更新,将会影响上一层(也就是进入这一层递归的那一层)的操作
// 可以说是将会化作一种收益来影响上一层递归后面的操作结果,然后再以此来继续影响上一层的上一层
// 这是递归一个很大的特点,就比如八皇后,也是利用了这个递归原理的。
// 而且这里为什么要加上这个判断呢?是因为lowTimeMark记录的能达到的最小时间戳是在不经过父节点的情况下的
// 所以为什么要加这个if,你懂的╮(╯▽╰)╭
if (edges.get(i).getEnd() != father) {
lowTimeMark[curennt] = lowTimeMark[curennt] > timeMark[edges
.get(i).getEnd()] ? timeMark[edges.get(i).getEnd()]
: lowTimeMark[curennt];
}
}
}
}
}
class Vertex {
private LinkedList<Edge> edges = new LinkedList<>();
private int id;
public Vertex() {
}
public LinkedList<Edge> getEdges() {
return edges;
}
public void setEdges(LinkedList<Edge> edges) {
this.edges = edges;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
class Edge implements Comparable<Edge> {
private int begin;
private int end;
private int weight;
public Edge() {
}
public Edge(int begin, int end, int weight) {
this.begin = begin;
this.end = end;
this.weight = weight;
}
public int getBegin() {
return begin;
}
public void setBegin(int begin) {
this.begin = begin;
}
public int getEnd() {
return end;
}
public void setEnd(int end) {
this.end = end;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
@Override
public String toString() {
return "Edge [begin=" + begin + ", end=" + end + ", weight=" + weight
+ "]";
}
@Override
public int compareTo(Edge o) {
if (this.weight > o.getWeight()) {
return 1;
}
return -1;
}
}
0 0
- 图的割点
- 图的割点
- 图的割点
- 图的割点
- 图的割点和割边
- 图的割点和割边
- 图的割点,割边
- 【模板】图的割点
- 求图的割点
- 图的割边、割点、块、缩点问题
- 图的割点与割边学习笔记
- 无向连通图的割点与割边
- 图的割点与割边实现
- 图的割点和割边-裸题
- 图的割点和桥
- 无向图的割点算法
- 求连通图的割点
- POJ1144-求图的割点(裸)
- 无缝轮播图
- C 进制转换程序
- Android自动测试:monkey使用
- Mr. Frog’s Problem(弱校联盟 十一专场)
- RS232电平与TTL电平转换
- 图的割点
- UVa 11624 - Fire!(BFS)
- Elasticsearch2.x 全文检索之——查询合并
- handler机制原理源码分析
- HDU 4436 后缀数组
- 框架入门 实战篇 (上)留言板前端整理
- 使用自制的框架完成的留言板完善
- Android、Java验证手机号是否合法
- uva- 156-Ananagrams