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 C (GCC 5.4.1) (judge verdict: Accepted)

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

typedef struct int_list_elem_t {
  int data;
  struct int_list_elem_t* prev;
  struct int_list_elem_t* next;
} int_list_elem;

typedef struct int_list_t {
  int_list_elem* head;
  int_list_elem* tail;
  unsigned long length;
} int_list;

int_list* int_list_init() {
  int_list* lst = (int_list*)calloc(1, sizeof(int_list));
  return lst;
}

unsigned long int_list_length(const int_list* lst) {
  return lst->length;
}
  
int int_list_get(const int_list* lst, unsigned long index) {
  if (lst->length <= index || index < 0) {
    printf("index out of range exception\n");
    exit(EXIT_FAILURE);
  }
  unsigned long i;
  int_list_elem* obtained_elem;
  if (index <= lst->length / 2) {
    obtained_elem = lst->head;
    for (i = 0; i < index; i++) {
      obtained_elem = obtained_elem->next;
    }
  } else {
    obtained_elem = lst->tail;
    for (i = lst->length - 1; i > index; i--) {
      obtained_elem = obtained_elem->prev;
    }
  }
  return obtained_elem->data;
}

void int_list_add(int_list* lst, unsigned long index, int data) {
  if (lst->length < index || index < 0) {
    printf("index out of range exception\n");
    exit(EXIT_FAILURE);
  }
  if (lst->length >= ULONG_MAX) {
    printf("list overflow\n");
    exit(EXIT_FAILURE);
  }

  int_list_elem* added_elem = (int_list_elem*)malloc(sizeof(int_list_elem));
  int_list_elem* elem;
  unsigned long i;
  added_elem->data = data;
  if (index == 0) {
    added_elem->prev = NULL;
    added_elem->next = lst->head;
    lst->head     = added_elem;
    if (added_elem->next == NULL) // if list length = 0
      lst->tail = added_elem;
    else
      added_elem->next->prev = added_elem;
  } else if (index == lst->length) {
    added_elem->next = NULL;
    added_elem->prev = lst->tail;
    lst->tail     = added_elem;
    // added_elem->prev != NULL because length != 0
    added_elem->prev->next = added_elem;
  } else {
    if (index <= lst->length / 2) {
      elem = lst->head;
      for (i = 0; i < index; i++) {
        elem = elem->next;
      }
    } else {
      elem = lst->tail;
      for (i = lst->length - 1; i > index; i--) {
        elem = elem->prev;
      }
    }
    elem->prev->next = added_elem;
    added_elem->prev = elem->prev;
    elem->prev       = added_elem;
    added_elem->next = elem;
  }
  lst->length++;
}

void int_list_remove(int_list* lst, unsigned long index) {
  if (lst->length <= index || index < 0) {
    printf("index out of range exception\n");
    exit(EXIT_FAILURE);
  }
  unsigned long i;
  int_list_elem* obtained_elem;
  if (index == 0) {
    obtained_elem = lst->head;
    lst->head = lst->head->next;
    if (lst->head == NULL)
      lst->tail = NULL;
    else
      lst->head->prev = NULL;
  } else if (index == lst->length - 1) {
    obtained_elem = lst->tail;
    lst->tail = lst->tail->prev;
    lst->tail->next = NULL;
  } else {
    if (index <= lst->length / 2) {
      obtained_elem = lst->head;
      for (i = 0; i < index; i++) {
        obtained_elem = obtained_elem->next;
      }
    } else {
      obtained_elem = lst->tail;
      for (i = lst->length - 1; i > index; i--) {
        obtained_elem = obtained_elem->prev;
      }
    }
    obtained_elem->prev->next = obtained_elem->next;
    obtained_elem->next->prev = obtained_elem->prev;
  }
  free(obtained_elem);
  lst->length--;
}

void int_list_delete(int_list* lst) {
  while (lst->length) {
    int_list_remove(lst, 0);
  }
  free(lst);
}

long count_one_stroke_path(int N, const int* pass, int_list** edge_list, int now) {
  long count = 0;
  int i, j;
  int next;
  int* next_pass;
  int goal = 1;
  int failure = 1;
  for (i = 0; i < N; i++) {
    if (pass[i] != 1) {
      goal = 0;
      break;
    }
  }
  if (goal) return 1;
  for (i = 0; i < edge_list[now]->length; i++) {
    next = int_list_get(edge_list[now], i);
    if (pass[next] == 0) {
      next_pass = (int*)malloc(sizeof(int) * N);
      for (j = 0; j < N; j++)
        next_pass[j] = pass[j];
      next_pass[next] = 1;
      count += count_one_stroke_path(N, next_pass, edge_list, next);
      failure = 0;
      free(next_pass);
    }
  }
  if (failure) return 0;
  return count;
}

int main() {
  int N, M;
  scanf("%d %d%*c", &N, &M);
  int* a, *b;
  a = (int*)malloc(sizeof(int) * M);
  b = (int*)malloc(sizeof(int) * M);
  int i, j;
  for (i = 0; i < M; i++) {
    scanf("%d %d%*c", &(a[i]), &(b[i]));
    a[i] -= 1;
    b[i] -= 1;
  }
  int_list** edge_list = (int_list**)malloc(sizeof(int_list*) * N);
  for (j = 0; j < N; j++) {
    edge_list[j] = int_list_init();
  }
  for (i = 0; i < M; i++) {
    for (j = 0; j < N; j++) {
      if (a[i] == j)
        int_list_add(edge_list[j], 0, b[i]);
      if (b[i] == j)
        int_list_add(edge_list[j], 0, a[i]);
    }
  }
  
  int* pass = (int*)calloc(N, sizeof(int));
  pass[0] = 1;
  printf("%ld\n", count_one_stroke_path(N, pass, edge_list, 0));
  
  
  free(a);
  free(b);
  for (j = 0; j < N; j++)
    int_list_delete(edge_list[j]);
  free(edge_list);
  free(pass);
  return 0;
}