图的割点

来源:互联网 发布:淘宝估值 编辑:程序博客网 时间: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