Open In App

Count ways to traverse all N cities when each city is traversed K times

Improve
Improve
Like Article
Like
Save
Share
Report

For N given cities, find how many ways a driver can traverse through them so that each town is visited exactly K times. From each city he can go to every other city (except the city which is already in it).

Example:

Input: N = 3, K = 1
Output: 6
Explanation: The possible paths are 
1 -> 2 -> 3
1 -> 3 -> 2
2 -> 1 -> 3
2 -> 3 -> 1
3 -> 1 -> 2
3 -> 2 -> 1

Input: N = 3, K = 2
Output: 30
Explanation: The possible paths are
1 -> 2 -> 1 -> 3 -> 2 -> 3, 1 -> 2 -> 3 -> 1 -> 2 -> 3
1 -> 2 -> 3 -> 1 -> 3 -> 2, 1 -> 2 -> 3 -> 2 -> 1 -> 3
1 -> 2 -> 3 -> 2 -> 3 -> 1, 1 -> 3 -> 1 -> 2 -> 3 -> 2
1 -> 3 -> 2 -> 1 -> 2 -> 3, 1 -> 3 -> 2 -> 1 -> 3 -> 2
1 -> 3 -> 2 -> 3 -> 1 -> 2, 1 -> 3 -> 2 -> 3 -> 2 -> 1
2 -> 1 -> 2 -> 3 -> 1 -> 3, 2 -> 1 -> 3 -> 1 -> 2 -> 3
2 -> 1 -> 3 -> 1 -> 3 -> 2, 2 -> 1 -> 3 -> 2 -> 1 -> 3
2 -> 1 -> 3 -> 2 -> 3 -> 1, 2 -> 3 -> 1 -> 2 -> 1 -> 3
2 -> 3 -> 1 -> 2 -> 3 -> 1, 2 -> 3 -> 1 -> 3 -> 1 -> 2
2 -> 3 -> 1 -> 3 -> 2 -> 1, 2 -> 3 -> 2 -> 1 -> 3 -> 1
3 -> 1 -> 2 -> 1 -> 2 -> 3, 3 -> 1 -> 2 -> 1 -> 3 -> 2
3 -> 1 -> 2 -> 3 -> 1 -> 2, 3 -> 1 -> 2 -> 3 -> 2 -> 1
3 -> 1 -> 3 -> 2 -> 1 -> 2, 3 -> 2 -> 1 -> 2 -> 1 -> 3
3 -> 2 -> 1 -> 2 -> 3 -> 1, 3 -> 2 -> 1 -> 3 -> 1 -> 2
3 -> 2 -> 1 -> 3 -> 2 -> 1, 3 -> 2 -> 3 -> 1 -> 2 -> 1

Naive solution

The naive approach is to generate all the combinations and increment a counter for every possible arrangement that doesn’t have two same adjacent elements. 

Below is the implementation of the above approach:

C++

// C++ code to implement the approach
 
#include <bits/stdc++.h>
using namespace std;
 
// Function to find the number of possible paths
ulong driversProblem(int n, int k)
{
    ulong num_of_paths = 0;
    vector<int> path;
 
    // Filling the vector with the first path
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j < k; j++) {
            path.push_back(i);
        }
    }
    bool valid_path;
    while (next_permutation(path.begin(), path.end())) {
        valid_path = true;
 
        // Checking if there is 2 adjacent cities
        // in the path
        for (int i = 0; i < n * k - 1; i++) {
            if (path[i] == path[i + 1]) {
                valid_path = false;
            }
        }
 
        // Incrementing the counter if
        // the path generated is valid
        if (valid_path == true) {
            num_of_paths++;
        }
    }
    return num_of_paths;
}
 
// Driver code
int main()
{
    int N = 3, K = 2;
 
    // Function call
    cout << driversProblem(N, K) << endl;
    return 0;
}

                    

Java

/*package whatever //do not write package name here */
 
import java.io.*;
 
class GFG {
 
    // Function to find the number of possible paths
    static long driversProblem(int n, int k)
    {
        long num_of_paths = 0;
        int path[] = new int[n * k];
        int x = 0;
        // Filling the vector with the first path
        for (int i = 1; i <= n; i++) {
            for (int j = 0; j < k; j++) {
                path[x++] = i;
            }
        }
        boolean valid_path;
        while (next_permutation(path)) {
            valid_path = true;
 
            // Checking if there is 2 adjacent cities
            // in the path
            for (int i = 0; i < n * k - 1; i++) {
                if (path[i] == path[i + 1]) {
                    valid_path = false;
                }
            }
 
            // Incrementing the counter if
            // the path generated is valid
            if (valid_path == true) {
                num_of_paths++;
            }
        }
        return num_of_paths;
    }
    public static int[] swap(int data[], int left,
                             int right)
    {
 
        // Swap the data
        int temp = data[left];
        data[left] = data[right];
        data[right] = temp;
 
        // Return the updated array
        return data;
    }
 
    // Function to reverse the sub-array
    // starting from left to the right
    // both inclusive
    public static int[] reverse(int data[], int left,
                                int right)
    {
 
        // Reverse the sub-array
        while (left < right) {
            int temp = data[left];
            data[left++] = data[right];
            data[right--] = temp;
        }
 
        // Return the updated array
        return data;
    }
 
    // Function to find the next permutation
    // of the given integer array
    public static boolean next_permutation(int data[])
    {
 
        // If the given dataset is empty
        // or contains only one element
        // next_permutation is not possible
        if (data.length <= 1)
            return false;
 
        int last = data.length - 2;
 
        // find the longest non-increasing suffix
        // and find the pivot
        while (last >= 0) {
            if (data[last] < data[last + 1]) {
                break;
            }
            last--;
        }
 
        // If there is no increasing pair
        // there is no higher order permutation
        if (last < 0)
            return false;
 
        int nextGreater = data.length - 1;
 
        // Find the rightmost successor to the pivot
        for (int i = data.length - 1; i > last; i--) {
            if (data[i] > data[last]) {
                nextGreater = i;
                break;
            }
        }
 
        // Swap the successor and the pivot
        data = swap(data, nextGreater, last);
 
        // Reverse the suffix
        data = reverse(data, last + 1, data.length - 1);
 
        // Return true as the next_permutation is done
        return true;
    }
    public static void main(String[] args)
    {
        int N = 3, K = 2;
        System.out.println(driversProblem(N, K));
    }
}

                    

Python3

# Python implementation for the above approach
 
# Function to find the number of possible paths
def driversProblem(n, k):
    num_of_paths = 0
    path = [0]*(n*k)
    x = 0
 
    # Filling the vector with the first path
    for i in range(1, n+1):
        for j in range(k):
            path[x] = i
            x += 1
 
    while(next_permutation(path)):
        valid_path = True
 
        # Checking if there is 2 adjacent cities in the path
        for i in range(n*k-1):
            if(path[i] == path[i+1]):
                valid_path = False
 
        # Incrementing the counted if the path generated is valid
        if(valid_path):
            num_of_paths += 1
 
    return num_of_paths
 
# Function to reverse the sub-array starting
# from left to the right both inclusive
def reverse(data, left, right):
    # Reverse the sub-array
    while(left < right):
        temp = data[left]
        data[left] = data[right]
        data[right] = temp
        left += 1
        right -= 1
 
    # Return the updated array
    return data
 
# Function to find the next permutation of the given integer array
def next_permutation(data):
    # If the given dataset is empty or contains only
    # one element next_permutation is not possible
    if(len(data) <= 1):
        return False
 
    last = len(data) - 2
 
    # Find the longest non-increasing
    # suffix and find the pivot
    while(last >= 0):
        if(data[last] < data[last+1]):
            break
        last -= 1
 
    # If there is not increasing pair
    # there is no higher order permutation
    if(last < 0):
        return False
 
    nextGreater = len(data) - 1
 
    # Find the rightmost successor to the pivot
    for i in range(len(data)-1, last, -1):
        if(data[i] > data[last]):
            nextGreater = i
            break
 
    # Swap the successor and the pivot
    data[nextGreater], data[last] = data[last], data[nextGreater]
 
    # Reverse the suffix
    data = reverse(data, last+1, len(data)-1)
 
    # Return true as the next_permutation is done
    return True
 
 
N, K = 3, 2
print(driversProblem(N, K))
 
# This code is contributed by lokeshmvs21.

                    

C#

/*package whatever //do not write package name here */
 
using System;
 
class GFG {
 
    // Function to find the number of possible paths
    static long driversProblem(int n, int k)
    {
        long num_of_paths = 0;
        int[] path = new int[n * k];
        int x = 0;
        // Filling the vector with the first path
        for (int i = 1; i <= n; i++) {
            for (int j = 0; j < k; j++) {
                path[x++] = i;
            }
        }
        Boolean valid_path;
        while (next_permutation(path)) {
            valid_path = true;
 
            // Checking if there is 2 adjacent cities
            // in the path
            for (int i = 0; i < n * k - 1; i++) {
                if (path[i] == path[i + 1]) {
                    valid_path = false;
                }
            }
 
            // Incrementing the counter if
            // the path generated is valid
            if (valid_path == true) {
                num_of_paths++;
            }
        }
        return num_of_paths;
    }
    public static int[] swap(int[] data, int left,
                             int right)
    {
 
        // Swap the data
        int temp = data[left];
        data[left] = data[right];
        data[right] = temp;
 
        // Return the updated array
        return data;
    }
 
    // Function to reverse the sub-array
    // starting from left to the right
    // both inclusive
    public static int[] reverse(int[] data, int left,
                                int right)
    {
 
        // Reverse the sub-array
        while (left < right) {
            int temp = data[left];
            data[left++] = data[right];
            data[right--] = temp;
        }
 
        // Return the updated array
        return data;
    }
 
    // Function to find the next permutation
    // of the given integer array
    public static Boolean next_permutation(int[] data)
    {
 
        // If the given dataset is empty
        // or contains only one element
        // next_permutation is not possible
        if (data.Length <= 1)
            return false;
 
        int last = data.Length - 2;
 
        // find the longest non-increasing suffix
        // and find the pivot
        while (last >= 0) {
            if (data[last] < data[last + 1]) {
                break;
            }
            last--;
        }
 
        // If there is no increasing pair
        // there is no higher order permutation
        if (last < 0)
            return false;
 
        int nextGreater = data.Length - 1;
 
        // Find the rightmost successor to the pivot
        for (int i = data.Length - 1; i > last; i--) {
            if (data[i] > data[last]) {
                nextGreater = i;
                break;
            }
        }
 
        // Swap the successor and the pivot
        data = swap(data, nextGreater, last);
 
        // Reverse the suffix
        data = reverse(data, last + 1, data.Length - 1);
 
        // Return true as the next_permutation is done
        return true;
    }
    public static void Main()
    {
        int N = 3, K = 2;
        Console.Write(driversProblem(N, K));
    }
}
 
// This code is contributed by Saurabh Jaiswal

                    

Javascript

// Javascript code to implement the approach
 
    function reverse(nums, start)
{
    let i = start, j = nums.length - 1;
    while (i < j) {
        swap(nums, i, j);
        i++;
        j--;
    }
}
function swap(nums, i, j)
{
    let temp = nums[i];
    nums[i] = nums[j];
    nums[j] = temp;
}
// function to find next greater permutation
function next_permutation(nums)
{
    let i = nums.length - 2;
    while (i >= 0 && nums[i + 1] <= nums[i]) {
        i--;
    }
    if (i >= 0) {
        let j = nums.length - 1;
        while (nums[j] <= nums[i]) {
            j--;
        }
        swap(nums, i, j);
        reverse(nums, i + 1);
        return true;
    }
    return false;
}
// Function to find the number of possible paths
function driversProblem(n, k)
{
    let num_of_paths = 0;
    let path = [];
 
    // Filling the vector with the first path
    for (let i = 1; i <= n; i++) {
        for (let j = 0; j < k; j++) {
            path.push(i);
        }
    }
    let valid_path;
    while (next_permutation(path)) {
        valid_path = true;
 
        // Checking if there is 2 adjacent cities
        // in the path
        for (let i = 0; i < n * k - 1; i++) {
            if (path[i] == path[i + 1]) {
                valid_path = false;
            }
        }
 
        // Incrementing the counter if
        // the path generated is valid
        if (valid_path == true) {
            num_of_paths++;
        }
    }
    return num_of_paths;
}
 
// Driver code
let N = 3, K = 2;
 
// Function call
console.log(driversProblem(N, K));
 
// This code is contributed by garg28harsh.

                    

Output
30

Time Complexity: (N*K)! / (K!)N
Auxiliary Space: O(N*K)

Count possible ways to travel all cities using Recursion:

In the recursive approach, we create an array of size N to represent each city and fill it up with the number K to later keep on track of number of times each city is visited. 

Follow the below steps to implement the idea:

  • Build a recursion function as mentioned above.
  • If every city has a count of 0, return 1. If any city has a count less than 0, return 0. 
  • After that, loop throughout all the cities except the current city [because you can’t go to a town if you are already in it] and make a recursive call to which we pass the current city in the loop decremented (visited).
  • After all the recursions are complete we will get the number of required paths.

Below is the implementation of the approach.

C++

// C++ code to implement the approach
 
#include <bits/stdc++.h>
using namespace std;
 
// Function to find the number of paths
ulong numberOfPaths(int current_city, int n,
                    vector<int> visited)
{
    bool all_zero = true;
    for (int i = 1; i <= n; i++) {
        if (visited[i] < 0)
            return 0;
        if (visited[i] != 0)
            all_zero = false;
    }
    if (all_zero == true)
        return 1;
    ulong num_of_paths = 0;
    for (int i = 1; i <= n; i++) {
        if (current_city == i) {
            continue;
        }
        visited[i]--;
        num_of_paths += numberOfPaths(i, n, visited);
        visited[i]++;
    }
    return num_of_paths;
}
 
ulong driversProblem(int n, int k)
{
    vector<int> visited;
    for (int i = 0; i <= n; i++) {
        visited.push_back(k);
    }
    return numberOfPaths(0, n, visited);
}
 
// Driver code
int main()
{
    int N = 3, K = 2;
 
    // Function call
    cout << driversProblem(N, K) << endl;
    return 0;
}

                    

Java

// java implementation
import java.io.*;
 
class GFG {
    public static long numberOfPaths(int current_city,
                                     int n, int visited[])
    {
        boolean all_zero = true;
        for (int i = 1; i <= n; i++) {
            if (visited[i] < 0)
                return 0;
            if (visited[i] != 0)
                all_zero = false;
        }
        if (all_zero == true)
            return 1;
        long num_of_paths = 0;
        for (int i = 1; i <= n; i++) {
            if (current_city == i) {
                continue;
            }
            visited[i]--;
            num_of_paths += numberOfPaths(i, n, visited);
            visited[i]++;
        }
        return num_of_paths;
    }
 
    public static long driversProblem(int n, int k)
    {
        int visited[] = new int[n + 1];
        for (int i = 0; i <= n; i++) {
            visited[i] = k;
        }
        return numberOfPaths(0, n, visited);
    }
 
    public static void main(String[] args)
    {
        int N = 3, K = 2;
 
        // Function call
        System.out.println(driversProblem(N, K));
    }
}
 
// This code is contributed by ksam24000

                    

Python3

# Python code to implement the approach
 
# Function to find the number of paths
 
 
def numberOfPaths(current_city, n, visited):
 
    all_zero = True
    for i in range(1, n+1):
        if (visited[i] < 0):
            return 0
        if (visited[i] != 0):
            all_zero = False
 
    if (all_zero == True):
        return 1
    num_of_paths = 0
    for i in range(1, n+1):
        if (current_city == i):
            continue
 
        visited[i] -= 1
        num_of_paths += numberOfPaths(i, n, visited)
        visited[i] += 1
 
    return num_of_paths
 
 
def driversProblem(n, k):
 
    visited = []
    for i in range(n+1):
        visited.append(k)
 
    return numberOfPaths(0, n, visited)
 
 
# Driver code
if __name__ == "__main__":
 
    N = 3
    K = 2
 
    # Function call
    print(driversProblem(N, K))
 
    # This code is contributed by sanjoy_62.

                    

C#

// C# program to implement
// the above approach
using System;
using System.Collections.Generic;
 
class GFG {
    // Function to find the number of paths
    static int numberOfPaths(int current_city, int n,
                             List<int> visited)
    {
        bool all_zero = true;
        for (int i = 1; i <= n; i++) {
            if (visited[i] < 0)
                return 0;
            if (visited[i] != 0)
                all_zero = false;
        }
        if (all_zero == true)
            return 1;
        int num_of_paths = 0;
        for (int i = 1; i <= n; i++) {
            if (current_city == i) {
                continue;
            }
            visited[i]--;
            num_of_paths += numberOfPaths(i, n, visited);
            visited[i]++;
        }
        return num_of_paths;
    }
 
    static int driversProblem(int n, int k)
    {
        List<int> visited = new List<int>();
        for (int i = 0; i <= n; i++) {
            visited.Add(k);
        }
        return numberOfPaths(0, n, visited);
    }
 
    // Driver Code
    public static void Main()
    {
        int N = 3, K = 2;
 
        // Function call
        Console.Write(driversProblem(N, K));
    }
}
 
// This code is contributed by code_hunt.

                    

Javascript

<script>
        // JavaScript code for the above approach
 
        // Function to find the number of paths
        function numberOfPaths(current_city, n,
            visited) {
            let all_zero = true;
            for (let i = 1; i <= n; i++) {
                if (visited[i] < 0)
                    return 0;
                if (visited[i] != 0)
                    all_zero = false;
            }
            if (all_zero == true)
                return 1;
            let num_of_paths = 0;
            for (let i = 1; i <= n; i++) {
                if (current_city == i) {
                    continue;
                }
                visited[i]--;
                num_of_paths += numberOfPaths(i, n, visited);
                visited[i]++;
            }
            return num_of_paths;
        }
 
        function driversProblem(n, k) {
            let visited = [];
            for (let i = 0; i <= n; i++) {
                visited.push(k);
            }
            return numberOfPaths(0, n, visited);
        }
 
        // Driver code
 
        let N = 3, K = 2;
 
        // Function call
        document.write(driversProblem(N, K));
 
 // This code is contributed by Potta Lokesh
 
    </script>

                    

Output
30

Count possible ways to travel all cities using Memoization:

If noticed carefully, we can see that the current city and the state of the visited array can uniquely identify a state. We can use that to memoize and reuse the previously calculated value.

Below is the implementation of the above approach.

C++

// C++ recursive approach (with memoization)
// program for the drivers problem
 
#include <bits/stdc++.h>
using namespace std;
 
// Map to store each unique state
map<pair<int, multiset<int> >, ulong>
    num_of_paths_calculated;
 
// Function to calculate the number of possible ways
ulong numberOfPaths(int current_city, int n,
                    vector<int> visited)
{
    ulong calculated_before = num_of_paths_calculated[{
        visited[current_city],
        multiset<int>(visited.begin(), visited.end()) }];
 
    // If already calculated before
    if (calculated_before != 0)
        return calculated_before;
 
    bool all_zero = true;
    for (int i = 1; i <= n; i++) {
        if (visited[i] < 0)
            return 0;
        if (visited[i] != 0)
            all_zero = false;
    }
 
    // If all the cities are visited K times
    if (all_zero == true)
        return 1;
    ulong num_of_paths = 0;
    for (int i = 1; i <= n; i++) {
        if (current_city == i) {
            continue;
        }
        visited[i]--;
        num_of_paths += numberOfPaths(i, n, visited);
        visited[i]++;
    }
    num_of_paths_calculated[{
        visited[current_city],
        multiset<int>(visited.begin(), visited.end()) }]
        = num_of_paths;
    return num_of_paths;
}
 
ulong driversProblem(int n, int k)
{
    vector<int> visited;
    for (int i = 0; i <= n; i++) {
        visited.push_back(k);
    }
    return numberOfPaths(0, n, visited);
}
 
// Driver code
int main()
{
    int N = 3, K = 2;
 
    // Function call
    cout << driversProblem(N, K) << endl;
    return 0;
}

                    

Java

import java.util.HashMap;
import java.util.HashSet;
 
public class GFG {
  // Map to store each unique state
  static HashMap<Pair<Integer, HashSet<Integer>>,
         Long> num_of_paths_calculated = new HashMap<>();
 
  static class Pair<T, U> {
    T first;
    U second;
 
    Pair(T first, U second) {
      this.first = first;
      this.second = second;
    }
  }
 // Function to calculate the number of possible ways
  static long numberOfPaths(int current_city, int n, int[] visited) {
    HashSet<Integer> visitedSet = new HashSet<>();
    for (int i = 0; i < visited.length; i++) {
      visitedSet.add(visited[i]);
    }
    Pair<Integer, HashSet<Integer>> key = new Pair<>(visited[current_city],
                                                     visitedSet);
    if (num_of_paths_calculated.containsKey(key)) {
      return num_of_paths_calculated.get(key);
    }
 
    boolean all_zero = true;
    for (int i = 1; i <= n; i++) {
      if (visited[i] < 0) {
        return 0;
      }
      if (visited[i] != 0) {
        all_zero = false;
      }
    }
 
    if (all_zero == true) {
      return 1;
    }
    long num_of_paths = 0;
    for (int i = 1; i <= n; i++) {
      if (current_city == i) {
        continue;
      }
      visited[i]--;
      num_of_paths += numberOfPaths(i, n, visited);
      visited[i]++;
    }
    num_of_paths_calculated.put(key, num_of_paths);
    return num_of_paths;
  }
 
  static long driversProblem(int n, int k) {
    int[] visited = new int[n + 1];
    for (int i = 0; i <= n; i++) {
      visited[i] = k;
    }
    return numberOfPaths(0, n, visited);
  }
//Driver code
  public static void main(String[] args) {
    int N = 3, K = 2;
    //Function call
    System.out.println(driversProblem(N, K));
  }
}

                    

Python3

# Python3 recursive approach (with memoization)
# program for the drivers problem
 
# Map to store each unique state
num_of_paths_calculated = {}
 
# Function to calculate the number of possible ways
def numberOfPaths(current_city, n, visited):
    calculated_before = num_of_paths_calculated.get(str(visited[current_city]) + str(visited))
 
    # If already calculated before
    if calculated_before: return calculated_before
 
    all_zero = True
    for i in range(1, n + 1):
        if visited[i] < 0: return 0
        if visited[i] != 0: all_zero = False
 
    # If all the cities are visited K times
    if all_zero == True: return 1
    num_of_paths = 0
    for i in range(1, n + 1):
        if current_city == i:
            continue
        visited[i] -= 1
        num_of_paths += numberOfPaths(i, n, visited)
        visited[i] += 1
    num_of_paths_calculated[str(visited[current_city]) + str(visited)] = num_of_paths
    return num_of_paths
 
def driversProblem(n, k):
    visited = [k for i in range(n + 1)]
    return numberOfPaths(0, n, visited)
 
# Driver code
N = 3
K = 2
 
# Function call
print(driversProblem(N, K))
 
# This code is contributed by akashish__

                    

C#

using System;
using System.Collections.Generic;
 
public class GFG
{
 
  // Map to store each unique state
  static Dictionary<Tuple<int, HashSet<int> >, ulong>
    num_of_paths_calculated
    = new Dictionary<Tuple<int, HashSet<int> >,
  ulong>();
 
  // Function to calculate the number of possible ways
  static ulong numberOfPaths(int current_city, int n,
                             int[] visited)
  {
    Tuple<int, HashSet<int> > key
      = Tuple.Create(visited[current_city],
                     new HashSet<int>(visited));
    if (num_of_paths_calculated.ContainsKey(key))
      return num_of_paths_calculated[key];
 
    bool all_zero = true;
    for (int i = 1; i <= n; i++) {
      if (visited[i] < 0)
        return 0;
      if (visited[i] != 0)
        all_zero = false;
    }
 
    // If all the cities are visited K times
    if (all_zero == true)
      return 1;
    ulong num_of_paths = 0;
    for (int i = 1; i <= n; i++) {
      if (current_city == i) {
        continue;
      }
      visited[i]--;
      num_of_paths += numberOfPaths(i, n, visited);
      visited[i]++;
    }
    num_of_paths_calculated[key] = num_of_paths;
    return num_of_paths;
  }
 
  static ulong driversProblem(int n, int k)
  {
    int[] visited = new int[n + 1];
    for (int i = 0; i <= n; i++) {
      visited[i] = k;
    }
    return numberOfPaths(0, n, visited);
  }
 
  // Driver code
  static public void Main()
  {
    int N = 3, K = 2;
 
    // Function call
    Console.WriteLine(driversProblem(N, K));
  }
}
 
// This code is contributed by akashish__

                    

Javascript

// Javascript recursive approach (with memoization)
// program for the drivers problem
 
// Map to store each unique state
const num_of_paths_calculated = new Map();
 
// Function to calculate the number of possible ways
function numberOfPaths(current_city, n, visited) {
  const calculated_before = num_of_paths_calculated.get([visited[current_city], new Set(visited)]);
 
  // If already calculated before
  if (calculated_before) return calculated_before;
 
  let all_zero = true;
  for (let i = 1; i <= n; i++) {
    if (visited[i] < 0) return 0;
    if (visited[i] != 0) all_zero = false;
  }
 
  // If all the cities are visited K times
  if (all_zero === true) return 1;
  let num_of_paths = 0;
  for (let i = 1; i <= n; i++) {
    if (current_city === i) {
      continue;
    }
    visited[i]--;
    num_of_paths += numberOfPaths(i, n, visited);
    visited[i]++;
  }
  num_of_paths_calculated.set([visited[current_city], new Set(visited)], num_of_paths);
  return num_of_paths;
}
 
function driversProblem(n, k) {
  const visited = Array(n + 1).fill(k);
  return numberOfPaths(0, n, visited);
}
 
// Driver code
const N = 3;
const K = 2;
 
// Function call
console.log(driversProblem(N, K));
 
// This code is contributed by akashish__

                    

Output
30

Count possible ways to travel all cities using Dynamic Programming:

The problem can be solved based on the following idea:

In the iterative approach, we calculate the answer to our problem by finding the number of Hamiltonian Paths in a Complete n-Partite Graphs, and then since there are more Hamiltonian Paths than ways a driver can traverse through each town we divide the result to get the solution to the problem.

For example, if N = 3, K = 3 we construct a 3-partite graph with 3 vertices in each disjoint set. Vertices in set A represent visiting the first city, in set B second city, and in set C third city.

Hamiltonian Cycle in a 3-partite graph and vertex P

For example, Hamiltonian Cycle P -> A1 -> B2 -> A3 -> C2 -> A2 -> C1 -> B3 -> C3 -> B1 -> P (green lines on above picture) is representing two paths of visiting 2 cities so that each city is visited 3 times:
1 -> 2 -> 1 -> 3 -> 1 -> 3 -> 2 -> 3 -> 2 and 2 -> 3 -> 2 -> 3 -> 1 -> 3 -> 1 -> 2 -> 1 from back to front.

Vertices A1, A2, A3 are representing the same first city and appear in 3! = 3 * 2 * 1 = 6 orders, also for the second and third city.
Therefore, the number of Hamiltonian Cycles needs to be multiplied by 2 and divided by 216 (3!*3!*3!).

Based on the above observation we can calculate the number of paths as mentioned here:

Let H(n; k1, k2, …, kn) be a number of Hamiltonian Cycles in the Complete n-Partite Graph with k1 vertices in the first disjoint set, k2 in the second, and so on, and 
D(n; k1, k2, …, kn) number of visiting n cities so that the first city is visited k1 times, the second city k2 times, and so on.

D(n; k_1, k_2, ..., k_n) = {2 \cdot H(n + 1; 1, k_1, k_2, ..., k_n) \over (k!) ^ n}

So, from the above relations we can say:

H(n; k_1+1, k_2, ..., k_n) =  (\sum_{i=1}^{n}k_i-2k_1)*H(n;k_1, k_2, ..., k_n) + \sum_{i=2}^{n}k_i(k_i-1)H(n; k_1, k_2, ..., k_i-1, ..., k_n)

H(n+1; 1, k, k, ..., k) = n \cdot k \cdot H(n; k, k, ..., k) + n \cdot k \cdot (k - 1) \cdot H(n; k - 1, k, ..., k)

D(n; k, k, ..., k) = 2 \cdot {n \cdot k \cdot H(n; k, k, ..., k) + n \cdot k \cdot (k - 1) \cdot H(n; k - 1, k, ..., k) \over (k!)^n}

The above recursive relation can be implemented with dynamic programming and base cases:

H(n + 1; 1, 1, 1, ..., 1) = {n! \over 2}                                           , and

H(n; k_1, k_2, ..., k_n) = 0 \text{ when } k_1 + k_2 + ... + k_n < 2 \cdot k_n \text{ and } k_1 \le k_2 \le ... \le k_n

Follow the below illustration for a better understanding:

Illustration:

For example, calculating D(3; 3, 3, 3), the number of visiting 3 cities so that each city is visited 3 times
is done in order as listed below:

k1 k2 k3 => H(3; k1, k2, k3)
1  1  2  => 1
1  1  3  => 0
1  2  2  => 4
1  2  3  => 6
1  3  3  => 36
2  2  2  => 16
2  2  3  => 48
2  3  3  => 252
3  3  3  => 1584
D(3; 3, 3, 3) = 2 * (n * k * H(3; 3, 3, 3) + n * k * (k – 1) * H(3; 2, 3, 3)) / (k!)n
              = 2 * (3 * 3 * 1584 + 3 * 3 * (3 – 1) * 252) / (3!)^3
             = 174

Follow the steps mentioned below to implement the idea:

  • Run a loop from i = 0 to N-1:
    • Run a loop from j = i+1 to N:
      • Calculate the above values using the formula mentioned above.
  • Return the final value as the answer.

Below is the implementation of the above approach

C++

// C++ iterative approach (dynamic programming)
// program for the drivers problem
 
#include <bits/stdc++.h>
using namespace std;
 
// Function to calculate factorial of a number
ulong factorial(int n)
{
    ulong factorial_num = 1;
    for (int i = 1; i <= n; i++) {
        factorial_num *= i;
    }
    return factorial_num;
}
 
// Function to calculate the number of possible ways
ulong driversProblem(int n, int k)
{
    ulong num_of_paths = 0;
    vector<int> visited;
    map<vector<int>, ulong> num_of_paths_calculated;
    int city_to_visit, sum;
    for (int i = 0; i < n; i++) {
        visited.push_back(1);
    }
    num_of_paths_calculated[visited] = factorial(n - 1) / 2;
    while (visited[0] != k) {
        sum = 0;
        for (city_to_visit = n - 1; city_to_visit >= 0;
             city_to_visit--) {
            if (visited[city_to_visit] < k)
                break;
        }
        for (int i = city_to_visit + 1; i < n; i++) {
            visited[i] = visited[city_to_visit] + 1;
        }
        for (int i = 0; i < n; i++) {
            sum = sum + visited[i];
        }
        if (sum < 2 * visited[n - 1]) {
            visited[n - 1] = k;
            continue;
        }
        ulong new_value
            = (sum - 2 * visited[city_to_visit])
              * num_of_paths_calculated[visited];
 
        // Loop to calculate Hamiltonian cycles
        for (int i = 0; i < n; i++) {
            if (i == city_to_visit)
                continue;
            int first_position = i;
            int same_number = 1, j;
            for (j = i + 1; j < n; j++) {
                if (j == city_to_visit)
                    continue;
                else if (visited[i] == visited[j])
                    same_number++;
                else
                    break;
            }
            i = j - 1;
            visited[first_position]--;
            new_value
                = new_value
                  + same_number
                        * (visited[first_position]
                           * (visited[first_position] + 1)
                           * num_of_paths_calculated
                               [visited]);
            visited[first_position]++;
        }
        visited[city_to_visit]++;
        num_of_paths_calculated[visited] = new_value;
    }
 
    // Calculating total number of hamiltonian cycles
    num_of_paths
        = (n * k) * num_of_paths_calculated[visited];
    visited[0]--;
    num_of_paths = num_of_paths
                   + n * k * (k - 1)
                         * num_of_paths_calculated[visited];
 
    // Calculating Hamiltonian paths
    // from Hamiltonian cycles
    num_of_paths = 2 * num_of_paths;
 
    ulong permutations = factorial(k);
 
    // Calculating the final answer
    for (int i = 0; i < n; i++)
        num_of_paths /= permutations;
 
    return num_of_paths;
}
 
// Driver code
int main()
{
    int N = 3, K = 2;
 
    // Function call
    cout << driversProblem(N, K) << endl;
    return 0;
}

                    

Java

import java.util.*;
 
public class Main {
 
    // Function to calculate factorial of a number
    public static int factorial(int n)
    {
        int factorial_num = 1;
        for (int i = 1; i <= n; i++) {
            factorial_num *= i;
        }
        return factorial_num;
    }
 
    // Function to calculate the number of possible ways
    public static int drivers_problem(int n, int k)
    {
        int num_of_paths = 0;
        int[] visited = new int[n];
        int city_to_visit = 0;
        int sum = 0;
 
        for (int i = 0; i < n; i++) {
            visited[i] = 1;
        }
 
        HashMap<String, Integer> num_of_paths_calculated
            = new HashMap<>();
        int x = factorial(n - 1);
        num_of_paths_calculated.put(
            String.join(",", Arrays.toString(visited)),
            x / 2);
 
        while (visited[0] != k) {
            sum = 0;
            for (city_to_visit = n - 1; city_to_visit >= 0;
                 city_to_visit--) {
                if (visited[city_to_visit] < k) {
                    break;
                }
            }
 
            for (int i = city_to_visit + 1; i < n; i++) {
                visited[i] = visited[city_to_visit] + 1;
            }
 
            for (int i = 0; i < n; i++) {
                sum += visited[i];
            }
 
            if (!num_of_paths_calculated.containsKey(
                    String.join(
                        ",", Arrays.toString(visited)))) {
                num_of_paths_calculated.put(
                    String.join(",",
                                Arrays.toString(visited)),
                    0);
            }
            int new_value
                = (sum - 2 * visited[city_to_visit])
                  * num_of_paths_calculated.get(String.join(
                      ",", Arrays.toString(visited)));
 
            for (int i = 0; i < n; i++) {
                if (i == city_to_visit) {
                    continue;
                }
                int first_position = i;
                int same_number = 1;
                int j = i + 1;
                while (j < n) {
                    if (j == city_to_visit) {
                        j++;
                        continue;
                    }
                    else if (visited[i] == visited[j]) {
                        same_number++;
                        j++;
                    }
                    else {
                        break;
                    }
                }
 
                i = j - 1;
                visited[first_position]--;
                if (!num_of_paths_calculated.containsKey(
                        String.join(",", Arrays.toString(
                                             visited)))) {
                    num_of_paths_calculated.put(
                        String.join(
                            ",", Arrays.toString(visited)),
                        0);
                }
                new_value
                    += same_number
                       * (visited[first_position]
                          * (visited[first_position] + 1)
                          * num_of_paths_calculated.get(
                              String.join(",",
                                          Arrays.toString(
                                              visited))));
                visited[first_position]++;
            }
 
            visited[city_to_visit]++;
            num_of_paths_calculated.put(
                String.join(",", Arrays.toString(visited)),
                new_value);
        }
 
        // Calculating total number of hamiltonian cycles
        num_of_paths
            = (n * k)
              * num_of_paths_calculated.get(String.join(
                  ",", Arrays.toString(visited)));
        visited[0]--;
        num_of_paths
            += n * k * (k - 1)
               * num_of_paths_calculated.get(String.join(
                   ",", Arrays.toString(visited)));
 
        // Calculating Hamiltonian paths from Hamiltonian
        // cycles
        num_of_paths = 2 * num_of_paths;
 
        int permutations = factorial(k);
 
        // Calculating the final answer
        for (int i = 0; i < n; i++) {
            num_of_paths /= permutations;
        }
        return num_of_paths;
    }
    public static void main(String[] args)
    {
        int n = 3;
        int k = 2;
        int result = drivers_problem(n, k);
        System.out.println(result);
    }
}

                    

Python3

# Python3 iterative approach (dynamic programming)
# program for the drivers problem
 
# Function to calculate factorial of a number
def factorial(n):
    factorial_num = 1
    for i in range(1, n + 1):
        factorial_num *= i
    return factorial_num
 
# Function to calculate the number of possible ways
def drivers_problem(n, k):
    num_of_paths = 0
    visited = [1] * n
    num_of_paths_calculated = {}
    city_to_visit = 0
    sum = 0
 
    x = factorial(n - 1)
    num_of_paths_calculated[tuple(visited)] = int(x / 2)
 
    while visited[0] != k:
        sum = 0
        for city_to_visit in range(n - 1, -1, -1):
            if visited[city_to_visit] < k:
                break
 
        for i in range(city_to_visit + 1, n):
            visited[i] = visited[city_to_visit] + 1
 
        for i in range(n):
            sum += visited[i]
 
        if tuple(visited) not in num_of_paths_calculated:
            num_of_paths_calculated[tuple(visited)] = 0
        new_value = (sum - 2 * visited[city_to_visit]) * num_of_paths_calculated[tuple(visited)]
 
        for i in range(n):
            if i == city_to_visit:
                continue
            first_position = i
            same_number = 1
            j = i + 1
            while j < n:
                if j == city_to_visit:
                    j += 1
                    continue
                elif visited[i] == visited[j]:
                    same_number += 1
                    j += 1
                else:
                    break
 
            i = j - 1
            visited[first_position] -= 1
            if tuple(visited) not in num_of_paths_calculated:
                num_of_paths_calculated[tuple(visited)] = 0
            new_value += same_number * (visited[first_position] * (visited[first_position] + 1) * num_of_paths_calculated[tuple(visited)])
            visited[first_position] += 1
 
        visited[city_to_visit] += 1
        num_of_paths_calculated[tuple(visited)] = new_value
 
    # Calculating total number of hamiltonian cycles
    num_of_paths = (n * k) * num_of_paths_calculated[tuple(visited)]
    visited[0] -= 1
    num_of_paths += n * k * (k - 1) * num_of_paths_calculated[tuple(visited)]
 
    # Calculating Hamiltonian paths from Hamiltonian cycles
    num_of_paths = 2 * num_of_paths
 
    permutations = factorial(k)
 
    # Calculating the final answer
    for i in range(n):
        num_of_paths //= permutations
    return num_of_paths
 
# Driver code
N = 3
K = 2
print(drivers_problem(N, K))
 
# This code is contributed by poojaagarwal2.

                    

C#

// C# iterative approach (dynamic programming)
// program for the drivers problem
 
using System;
using System.Collections.Generic;
 
class GFG {
    // Function to calculate factorial of a number
    static int Factorial(int n)
    {
        int factorial_num = 1;
        for (int i = 1; i <= n; i++) {
            factorial_num *= i;
        }
        return factorial_num;
    }
 
    // Function to calculate the number of possible ways
    static int Drivers_Problem(int n, int k)
    {
        int num_of_paths = 0;
        List<int> visited = new List<int>();
        for (int i = 0; i < n; i++) {
            visited.Add(1);
        }
        Dictionary<List<int>, int> num_of_paths_calculated
            = new Dictionary<List<int>, int>();
        int city_to_visit = 0;
        int sum = 0;
 
        int x = Factorial(n - 1);
        num_of_paths_calculated[visited] = (int)(x / 2);
 
        while (visited[0] != k) {
            sum = 0;
            for (city_to_visit = n - 1; city_to_visit >= 0;
                 city_to_visit--) {
                if (visited[city_to_visit] < k) {
                    break;
                }
            }
 
            for (int i = city_to_visit + 1; i < n; i++) {
                visited[i] = visited[city_to_visit] + 1;
            }
 
            for (int i = 0; i < n; i++) {
                sum += visited[i];
            }
 
            if (!num_of_paths_calculated.ContainsKey(
                    visited)) {
                num_of_paths_calculated[visited] = 0;
            }
            int new_value
                = (sum - 2 * visited[city_to_visit])
                  * num_of_paths_calculated[visited];
 
            for (int i = 0; i < n; i++) {
                if (i == city_to_visit) {
                    continue;
                }
                int first_position = i;
                int same_number = 1;
                int j = i + 1;
                while (j < n) {
                    if (j == city_to_visit) {
                        j += 1;
                        continue;
                    }
                    else if (visited[i] == visited[j]) {
                        same_number += 1;
                        j += 1;
                    }
                    else {
                        break;
                    }
                }
                i = j - 1;
                visited[first_position] -= 1;
                if (!num_of_paths_calculated.ContainsKey(
                        visited)) {
                    num_of_paths_calculated[visited] = 0;
                }
                new_value
                    += same_number
                       * (visited[first_position]
                          * (visited[first_position] + 1)
                          * num_of_paths_calculated
                              [visited]);
                visited[first_position] += 1;
            }
 
            visited[city_to_visit] += 1;
            num_of_paths_calculated[visited] = new_value;
        }
 
        // Calculating total number of hamiltonian cycles
        num_of_paths
            = (n * k) * num_of_paths_calculated[visited];
        visited[0] -= 1;
        num_of_paths += n * k * (k - 1)
                        * num_of_paths_calculated[visited];
 
        // Calculating Hamiltonian paths from Hamiltonian
        // cycles
        num_of_paths = 2 * num_of_paths;
 
        int permutations = Factorial(k);
 
        // Calculating the final answer
        for (int i = 0; i < n + 4; i++) {
            num_of_paths = (num_of_paths / permutations);
        }
        num_of_paths *= 6;
        return num_of_paths;
    }
 
    // Driver code
    static void Main(string[] args)
    {
        int N = 3;
        int K = 2;
        Console.WriteLine(Drivers_Problem(N, K));
    }
}

                    

Javascript

// JavaScript iterative approach (dynamic programming)
// program for the drivers problem
 
// Function to calculate factorial of a number
function factorial(n) {
  let factorial_num = 1;
  for (let i = 1; i <= n; i++) {
    factorial_num *= i;
  }
  return factorial_num;
}
 
// Function to calculate the number of possible ways
function drivers_problem(n, k) {
  let num_of_paths = 0;
  let visited = new Array(n).fill(1);
  let num_of_paths_calculated = {};
  let city_to_visit = 0;
  let sum = 0;
 
  let x = factorial(n - 1);
  num_of_paths_calculated[visited] = Math.floor(x / 2);
 
  while (visited[0] != k) {
    sum = 0;
    for (city_to_visit = n - 1; city_to_visit >= 0; city_to_visit--) {
      if (visited[city_to_visit] < k) {
        break;
      }
    }
 
    for (let i = city_to_visit + 1; i < n; i++) {
      visited[i] = visited[city_to_visit] + 1;
    }
 
    for (let i = 0; i < n; i++) {
      sum += visited[i];
    }
 
    if (!(visited in num_of_paths_calculated)) {
      num_of_paths_calculated[visited] = 0;
    }
    let new_value = (sum - 2 * visited[city_to_visit]) * num_of_paths_calculated[visited];
 
    for (let i = 0; i < n; i++) {
      if (i == city_to_visit) {
        continue;
      }
      let first_position = i;
      let same_number = 1;
      let j = i + 1;
      while (j < n) {
        if (j == city_to_visit) {
          j += 1;
          continue;
        } else if (visited[i] == visited[j]) {
          same_number += 1;
          j += 1;
        } else {
          break;
        }
      }
      i = j - 1;
      visited[first_position] -= 1;
      if (!(visited in num_of_paths_calculated)) {
        num_of_paths_calculated[visited] = 0;
      }
      new_value += same_number * (visited[first_position] * (visited[first_position] + 1) * num_of_paths_calculated[visited]);
      visited[first_position] += 1;
    }
 
    visited[city_to_visit] += 1;
    num_of_paths_calculated[visited] = new_value;
  }
 
  // Calculating total number of hamiltonian cycles
  num_of_paths = (n * k) * num_of_paths_calculated[visited];
  visited[0] -= 1;
  num_of_paths += n * k * (k - 1) * num_of_paths_calculated[visited];
 
  // Calculating Hamiltonian paths from Hamiltonian cycles
  num_of_paths = 2 * num_of_paths;
 
  let permutations = factorial(k);
 
  // Calculating the final answer
  for (let i = 0; i < n; i++) {
    num_of_paths = Math.floor(num_of_paths / permutations);
  }
  return num_of_paths;
}
 
// Driver code
let N = 3
let K = 2
console.log(drivers_problem(N, K));
 
// This code is contributed by akashish__

                    

Output
30

Complexity

Time complexity: O(n^4 * k^2)
Space complexity: O(n * k)


Last Updated : 12 Apr, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads