Problem:
Score : 300 points

Problem Statement

You are given an undirected unweighted graph with N vertices and M edges that contains neither self-loops nor double edges.

Here, a self-loop is an edge where a_i = b_i (1≤i≤M), and double edges are two edges where (a_i,b_i)=(a_j,b_j) or (a_i,b_i)=(b_j,a_j) (1≤i<j≤M).

How many different paths start from vertex 1 and visit all the vertices exactly once?

Here, the endpoints of a path are considered visited.

For example, let us assume that the following undirected graph shown in Figure 1 is given.

Figure 1: an example of an undirected graph

The following path shown in Figure 2 satisfies the condition.

Figure 2: an example of a path that satisfies the condition

However, the following path shown in Figure 3 does not satisfy the condition, because it does not visit all the vertices.

Figure 3: an example of a path that does not satisfy the condition

Neither the following path shown in Figure 4, because it does not start from vertex 1.

Figure 4: another example of a path that does not satisfy the condition

Constraints

2≦N≦8

0≦M≦N(N-1)/2

1≦a_i<b_i≦N

The given graph contains neither self-loops nor double edges.

Input

The input is given from Standard Input in the following format:

N M
a_1 b_1
a_2 b_2
:
a_M b_M

Output

Print the number of the different paths that start from vertex 1 and visit all the vertices exactly once.

Sample Input 1

3 3
1 2
1 3
2 3

Sample Output 1

2

The given graph is shown in the following figure:

The following two paths satisfy the condition:

Sample Input 2

7 7
1 3
2 7
3 4
4 5
4 6
5 6
6 7

Sample Output 2

1

This test case is the same as the one described in the problem statement.

Solution in Java (OpenJDK 11.0.6) (judge verdict: Accepted)

import java.util.*;
import java.util.stream.*;

public class Main {

	public static void main(String[] args){
		
		// 方針：タブーリスト付きの深さ優先探索、この手に限る
		
		// 隣接行列、0か1なのでbooleanで十分
		boolean[][] adjacencyMatrix = createAdjacencyMatrix();
		int n= adjacencyMatrix.length;
		// 訪問履歴、タブーリスト
		boolean[] history = new boolean[n];
		// 1番のノード（インデックスの0）から探索を始めるよ
		history[0] = true;
		int eulerianTrailNum = traverseAndCountEulerianTrail(0, adjacencyMatrix, history);
		System.out.println(eulerianTrailNum);
		
	}
	
	// 入力から隣接行列を作る
	public static boolean[][] createAdjacencyMatrix(){
		
		Scanner scan = new Scanner(System.in);
		
		int n = scan.nextInt();
		int m = scan.nextInt();
		
		boolean[][] ret = new boolean[n][n];
		
		IntStream.range(0, m)
			.forEach(nouse -> {
				// 配列の番号じゃなくて、ノード番号で渡されるので-1
				int p = scan.nextInt() - 1;
				int q = scan.nextInt() - 1;
				ret[p][q] = true;
				ret[q][p] = true;
			});
		
		scan.close();
		return ret;
		
	}
	
	public static int traverseAndCountEulerianTrail(int currentNode, boolean[][] adjacencyMatrix, boolean[] history) {
		
		history[currentNode] = true;
		
		int n = history.length;
		// ここがゴールだったみたいです。1本見つけましたよ
		if(IntStream.range(0, n).boxed().allMatch(index -> history[index])) {
			history[currentNode] = false;
			return 1;
		}
		
		// ゴールじゃなかったので再帰して木探索してきてね
//		return IntStream.range(0, n)
		int ans  = IntStream.range(0, n)
						// 隣接してて、行ったことのないところに行きたい
						.filter(index -> adjacencyMatrix[currentNode][index] && history[index] == false)
						// map関数の中でhistoryトグルさせるのは予期できない挙動なので本当は嫌
						.map(index -> {
//							history[index] = true;
							// 再帰していってきます
							int num = traverseAndCountEulerianTrail(index, adjacencyMatrix, history);
							// 深さ優先探索なので配列を使いまわせる
//							history[index] = false;
							return num;
						})
						.sum();
		
		history[currentNode] = false;
		
		return ans;
		
	}

}