不带权图

一、拓扑排序

    对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序

拓扑排序算法主要是循环执行以下两步,直到不存在入度为0的顶点为止。

(1) 选择一个入度为0的顶点并输出之;

(2) 从网中删除此顶点及所有出边

循环结束后,若输出的顶点数小于网中的顶点数,则输出“有回路”信息,否则输出的顶点序列就是一种拓扑序列

算法代码如下:

package _不带权图;

import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
//拓扑排序
public class _拓扑排序 {

	static int n;//顶点个数
	static int[] indegree;//用于记录顶点入度的信息
	static LinkedList<Integer>[] list;//邻接表存图

	//初始化
	static void init() {
		indegree = new int[n + 1];
		list = new LinkedList[n + 1];
		for (int i = 0; i < n + 1; i++)
			list[i] = new LinkedList<Integer>();

	}

	//拓扑排序
	static void topo() {
		Queue<Integer> q = new LinkedList<>();//用队列存储入度为0的顶点
		for (int i = 1; i <= n; i++) {//找出起点
			if (indegree[i] == 0) {
				q.offer(i);
			}
		}
		while (!q.isEmpty()) {
			int u = q.poll();
			System.out.println(u);
			for (int i = 0; i < list[u].size(); i++) {
				int v = list[u].get(i);
				indegree[v]--;//与u顶点相连的顶点度数减一
				if(indegree[v]==0) {//如果有度数为0的点,入队
					q.offer(v);
				}
			}
		}
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub

		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		int m = sc.nextInt();
		init();
		int u, v;
		for (int i = 1; i <= m; i++) {
			u = sc.nextInt();
			v = sc.nextInt();
			list[u].add(v);
			indegree[v]++;
		}
		topo();
	}

}

 二 、欧拉回路与欧拉路径

     从七桥问题开始

若图G中存在这样一条路径,使得恰好通过图G中每条边一次,则称该路径为欧拉路径。

若该路径是一个环路,则称为欧拉回路。

具有欧拉回路的图称为欧拉图。

具有欧拉路径但不具有欧拉回路的图称为半欧拉图。

 即

无向图欧拉路径:

* 连通图,图中有2个奇度顶点,或无奇度顶点。 如果有2个奇度顶点,那么这2个顶点是欧拉路径的端点。

无向图欧拉回路:

* 连通图,图中不存在奇度顶点。

 有向图欧拉路径:

所有点的入度和出度相同,或者 有一个顶点出度与入度差为1,一个顶点出度与入度差为-1,其余入度与出度顶点相等(即差值为0)。

有向图欧拉回路:

所有顶点的入度与出度相等。

 无向图

代码如下:

package _不带权图;

import java.util.LinkedList;
import java.util.Scanner;

//无向连通图
public class _欧拉回路和欧拉路径 {

	static int n, m, cnt;
	static int[] degree;
	static boolean[] vis;
	static LinkedList<Integer>[] list;

	static void init() {
		degree = new int[n + 1];
		vis = new boolean[n + 1];
		list = new LinkedList[n + 1];
		for (int i = 0; i <= n; i++)
			list[i] = new LinkedList<>();
	}

	// 判断图是否连通
	static void dfs(int u) {
		vis[u] = true;
		cnt++;
		for (int i = 0; i < list[u].size(); i++) {
			int v = list[u].get(i);
			if (!vis[v]) {
				dfs(v);
			}
		}
	}

	static void euler() {
		dfs(1);
		//判断图是否连通
		if (cnt != n) {
			System.out.println("It not euler");
			return;
		}
		int cntodd = 0;// 记录度为奇数点的个数
		for (int i = 1; i <= n; i++) {
			if (degree[i] % 2 == 1) {
				cntodd++;
			}
		}

		if (cntodd == 0) {//无奇度顶点
			System.out.println("有euler回路");
		} else if (cntodd == 2) {//奇度顶点个数为2
			System.out.println("有欧拉路径");
		} else {
			System.out.println("无欧拉路径");
		}
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub

		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		m = sc.nextInt();
		init();
		int u, v;
		for (int i = 0; i < m; i++) {
			u = sc.nextInt();
			v = sc.nextInt();
			list[u].add(v);
			list[v].add(u);
			degree[u]++;
			degree[v]++;
		}
		euler();
	}

}

有向图

代码如下:

package _不带权图;

import java.util.LinkedList;
import java.util.Scanner;

public class _有向图的欧拉回路和欧拉路径判断 {

	static int n, m;
	static int[] degree;
	static LinkedList<Integer>[] list;

	//初始化
	static void init() {
		degree = new int[n + 1];
		list = new LinkedList[n + 1];
		for (int i = 0; i < n + 1; i++) {
			list[i] = new LinkedList<>();
		}
	}

	static int euler() {
		int first = 0, last = 0;// first代表差值为-1的点,last代表差值为1的点
		for (int i = 1; i <= n; i++) {
			if (degree[i] < -1 || degree[i] > 1) {//差值为0
				System.out.println("无欧拉路径");
				return 0;
			} else if (degree[i] == -1) {
				if (first != 0) {//first已经被赋值,即有2个差值为-1的点
					System.out.println("无欧拉路径");
					return 0;
				} else {
					first = i;
				}
			} else if (degree[i] == 1) {
				if (last != 0) {
					System.out.println("No euler path");
					return 0;
				} else {
					last = i;
				}
			}
		}
		if (first == 0 && last == 0) {
			System.out.println("有欧拉回路");
		} else if (first != 0 && last != 0) {
			System.out.println("有欧拉路径");
			return first;
		}
		return 0;
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub

		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		m = sc.nextInt();
		init();
		int u, v;
		for (int i = 0; i < m; i++) {
			u = sc.nextInt();
			v = sc.nextInt();
			list[u].add(v);
			degree[u]--;
			degree[v]++;
		}
		euler();
	}

}

计算无向图的欧拉路经可以用“套圈法”、基于深度优先搜索来实现。从一个合适的顶点出发进行深度优先搜索。

 当搜到一个顶点u时:
       1.如果此时没有顶点与该顶点相连,那么就将u加入路径中并回溯;
       2.如果有顶点v与顶点u相连,那么就删除无向边<u,v>,并继续搜索顶点v。将所有和u相邻的顶点遍历完之后,将u加入路径中。

无向图求出欧拉回路的节点:

package _不带权图;

import java.util.Scanner;

public class _无向图欧拉回路搜索 {

	static int n, m, maxn = 100;
	static int[][] mat = new int[maxn][maxn];
	static int[] match = new int[maxn];// 顶点剩余的度

	static void solve(int u) {
		if (match[u] > 0) {
			for (int i = 0; i < n; i++) {
				if (mat[u][i] > 0) {
					mat[u][i]--;
					mat[i][u]--;
					solve(i);
				}
			}
		}
		System.out.println(u);
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub

		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		m = sc.nextInt();
	}

}

计算有向图的欧拉路经同样可以用“套圈法”。和无向图唯一不同的是,在记录方案的时候将顶点编号插入栈中,并在最后将栈中的元素依次输出。也就是说,将之前输出的顺序逆置。

有向图:

package _不带权图;

import java.util.LinkedList;
import java.util.Scanner;
import java.util.Stack;

public class _欧拉回路搜索算法 {

	static int n, m;
	static int[] degree;
	static LinkedList<Integer>[] list;
	static Stack<Integer> stack=new Stack<>();

	static void init() {
		degree=new int[n+1];
		list=new LinkedList[n+1];
		for(int i=0;i<=n;i++)
			list[i]=new LinkedList<Integer>();
	}
	//寻找欧拉回路的起点
	public static int Euler() {
		int first = 0, last = 0;
		for (int i = 1; i <= n; i++) {
			if (degree[i] < -1 || degree[i] > 1) {
				return 0;
			} else if (degree[i] == 1) {
				if (first != 0)
					return 0;
				else
					first = i;
			} else if (degree[i] == -1) {
				if (last != 0)
					return 0;
				else
					last = i;
			}

		}
		if (first == 0 && last == 0)
			return 1;
		else if (first != 0 && last != 0)
			return first;
		else 
			return 0;
	}
	//判断是否有欧拉回路
	static boolean euler_find() {
		int start;
		start=Euler();
		if(start==0)
			return false;
		else {
			dfs(start);
			return true;
		}
	}

	//dfs一遍,找出欧拉路径,用栈存储路径节点
	public static void dfs(int u) {
		for(int i=0;i<list[u].size();i++) {
			int v=list[u].get(i);
			dfs(v);
		}
		stack.add(u);
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub

		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		m = sc.nextInt();
		init();
		for (int i = 0; i < m; i++) {
			int u = sc.nextInt();
			int v = sc.nextInt();
			list[u].add(v);
			degree[v]++;
			degree[u]--;
		}
		if(!euler_find()) {
			System.out.println("No has");
		}else {
			while(!stack.isEmpty()) {
				System.out.println(stack.pop());
			}
		}
	}

}
发布了133 篇原创文章 · 获赞 31 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_41921315/article/details/89394687