Open In App

Expected number of coins after K moves

Last Updated : 09 Apr, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

Given an undirected graph of V nodes and E edges and an array coins[] of size V, such that coins[i] = number of coins present at ith node. Initially, choose any node uniformly at random and pick all the coins available on that node. In one move, we can move from the current node to any of its neighboring nodes. The task is to find the expected number of coins we can collect after K moves. Return the answer mod 109+7.

Note: 0-Based Indexing is followed in array i.e. coins[0] denotes the number of coins at node 1.

Examples:

Input: V = 4, E = 4, K = 1, edges[][] = {{0, 1}, {1, 2}, {2, 0}, {2, 3}}, coins[] = {1, 1, 1, 2}
Output: 333333338
Explanation:

  • If we start from node 0, then we will get 1 coin from node 0. In first move, we can either move to node 1 and collect 1 coin or move to node 2 and collect 1 coin. Therefore, the expected number of coins after 1 move starting from node 0 is (1 + 1/2 * (1 + 1)) = 2.
  • If we start from node 1, then we will get 1 coin from node 1. In first move, we can either move to node 0 and collect 1 coin or move to node 2 and collect 1 coin. Therefore, the expected number of coins after 1 move starting from node 1 is (1 + 1/2 * (1 + 1)) = 2.
  • If we starts with node 2, then we will get 1 coin from node 2. In the first move, we have 3 choices to make: move to node 0 and collect 1 coin, move to node 1 and collect 1 coin or move to node 4 and collect 2 coins. Therefore, the expected number of coins after 1 move starting from node 2 is (1 + 1/3 * (1 + 1 + 2)) = 7/3.
  • If we starts with node 3, then we will get 2 coins from node 3. In the first move, we can only move to node 2 and collect 1 coin. Therefore, the expected number of coins after 1 move starting from node 3 will be (2 + 1) = 3.

Since the probability to choose any node as the starting node is (1/4), the expected number of coins are: 1/4 * (2 + 2 + 7/3 + 3) mod (109 + 7) = 333333338

Input: V = 4, E = 4, K = 0, edges[][] = {{0, 1}}, coins[] = {2, 2}
Output: 2
Explanation: Since we cannot make any moves, we can only choose the starting node and collect its coin.

  • If we start from node 0, we will get 2 coins.
  • If we start from node 1, we will get 2 coins.

Since the probability to choose any node as the starting node is (1/2), the expected number of coins are: 1 / 2 * (2 + 2) mod (109 + 7) = 2.

Approach: To solve the problem, follow the below idea:

The problem can be solved using Depth First Search and Dynamic Programming. We can run a DFS starting from every node and keeping track of the number of moves left. Also maintain a 2D array dp[][] such that dp[i][j] = expected number of coins if we are at node i and have j moves remaining.

Step-by-step algorithm:

  • Create a adjacency matrix graph from edges[][] and create a dp[][] to store the number of coins.
  • Iterate in vertices:
    • Call the dfs() function for each vertices present.
    • Also, mark the node visited.
  • Iterate in adjacent nodes:
    • Get the number of children for each node.
    • Call the dfs() function for adjacent nodes.
  • If number of children are zero, return number of coins present on that node.
  • If number of coins from adjacent nodes are divisible by number of children return a[node] + (temp / nchild).
  • Else, return dfs(child, graph, visited, a, k – 1, dp).
  • store it in dp.

Below is the implementation of the algorithm:

C++
#include <bits/stdc++.h>

using namespace std;

int mod = 1e9 + 7;

// Function to calculate mod
long long powermod(int a, int m)
{
    if (a == 0)
        return 1;
    if (m == 1)
        return a % mod;

    long long temp = powermod(a, m / 2) % mod;
    temp = (temp * temp) % mod;

    return m % 2 == 0 ? temp : (a * temp) % mod;
}

// Function to start iterating from particular node
int dfs(int node, vector<vector<int> >& graph,
        vector<bool>& visited, vector<int>& coins, int K,
        vector<vector<int> >& dp)
{
    // If number of second becomes 0
    if (K == 0)
        return coins[node];

    // If that particular node is already calculated
    if (dp[node][K] != -1)
        return dp[node][K];

    // Get the number of children
    int nchild = graph[node].size();
    int temp = 0;

    // Iterate to all the adjacent nodes
    for (int child : graph[node]) {

        // Iterate further in nodes
        temp = (temp
                + dfs(child, graph, visited, coins, K - 1,
                    dp))
            % mod;
    }

    // If adjacent nodes are zero
    if (nchild == 0)
        temp = coins[node];
    else
        temp = ((coins[node] * nchild + temp)
                * powermod(nchild, mod - 2))
            % mod;

    // Store the coins in dp
    return dp[node][K] = temp;
}

// Functions to find number of coins we can achieve
int expectedCoins(int V, int E, vector<int>& a,
                vector<vector<int> >& edges, int k)
{
    // Declare a vector graph
    vector<vector<int> > graph(V);
    vector<vector<int> > dp(V, vector<int>(k + 1, -1));

    // Create a adjancy matrix
    for (auto e : edges) {

        graph[e[0]].push_back(e[1]);
        graph[e[1]].push_back(e[0]);
    }

    // Iterate in vertices
    int ans = 0;
    for (int i = 0; i < V; i++) {

        // Intialize a vector visited
        vector<bool> visited(V, false);

        // Call the dfs function
        int temp = dfs(i, graph, visited, a, k, dp);

        // Add number of coins to ans
        ans = (ans + temp) % mod;
    }

    if (ans % V == 0)
        return (ans / V) % mod;
    ans = (ans * powermod(V, mod - 2)) % mod;

    return ans;
}

// Driver code
int main()
{
    int V = 4;
    int E = 4;
    int K = 1;
    vector<vector<int> > edges
        = { { 0, 1 }, { 0, 2 }, { 1, 2 }, { 2, 3 } };
    vector<int> coins = { 1, 1, 1, 2 };

    // Function call
    cout << expectedCoins(V, E, coins, edges, K);

    return 0;
}
Java
import java.util.*;

public class Main {
    static int mod = (int)1e9 + 7;

    // Function to calculate mod
    static long powermod(int a, int m) {
        if (a == 0)
            return 1;
        if (m == 1)
            return a % mod;

        long temp = powermod(a, m / 2) % mod;
        temp = (temp * temp) % mod;

        return m % 2 == 0 ? temp : (a * temp) % mod;
    }

    // Function to start iterating from particular node
    static long dfs(int node, ArrayList<ArrayList<Integer>> graph,
                   boolean[] visited, int[] coins, int K,
                   long[][] dp) {
        // If number of second becomes 0
        if (K == 0)
            return coins[node];

        // If that particular node is already calculated
        if (dp[node][K] != -1)
            return dp[node][K];

        // Get the number of children
        int nchild = graph.get(node).size();
        long temp = 0;

        // Iterate to all the adjacent nodes
        for (int child : graph.get(node)) {
            // Iterate further in nodes
            temp = (temp
                    + dfs(child, graph, visited, coins, K - 1,
                          dp))
                   % mod;
        }

        // If adjacent nodes are zero
        if (nchild == 0)
            temp = coins[node];
        else
            temp = ((coins[node] * nchild + temp)
                    * powermod(nchild, mod - 2))
                   % mod;

        // Store the coins in dp
        return dp[node][K] = temp;
    }

    // Functions to find number of coins we can achieve
    static long expectedCoins(int V, int E, int[] a,
                             int[][] edges, int k) {
        // Declare a vector graph
        ArrayList<ArrayList<Integer>> graph = new ArrayList<>();
        for(int i=0; i<V; i++) {
            graph.add(new ArrayList<>());
        }
        long[][] dp = new long[V][k + 1];
        for(long[] row : dp) {
            Arrays.fill(row, -1);
        }

        // Create a adjacency matrix
        for (int[] e : edges) {
            graph.get(e[0]).add(e[1]);
            graph.get(e[1]).add(e[0]);
        }

        // Iterate in vertices
        long ans = 0;
        for (int i = 0; i < V; i++) {
            // Initialize a vector visited
            boolean[] visited = new boolean[V];

            // Call the dfs function
            long temp = dfs(i, graph, visited, a, k, dp);

            // Add number of coins to ans
            ans = (ans + temp) % mod;
        }

        if (ans % V == 0)
            return (ans / V) % mod;
        ans = (ans * powermod(V, mod - 2)) % mod;

        return ans;
    }

    // Driver code
    public static void main(String[] args) {
        int V = 4;
        int E = 4;
        int K = 1;
        int[][] edges = { { 0, 1 }, { 0, 2 }, { 1, 2 }, { 2, 3 } };
        int[] coins = { 1, 1, 1, 2 };

        // Function call
        System.out.println(expectedCoins(V, E, coins, edges, K));
    }
}
Python3
mod = 10**9 + 7

# Function to calculate mod
def powermod(a, m):
    if a == 0:
        return 1
    if m == 1:
        return a % mod

    temp = powermod(a, m // 2) % mod
    temp = (temp * temp) % mod

    return temp if m % 2 == 0 else (a * temp) % mod

# Function to start iterating from a particular node
def dfs(node, graph, visited, coins, K, dp):
    # If the number of seconds becomes 0
    if K == 0:
        return coins[node]

    # If that particular node is already calculated
    if dp[node][K] != -1:
        return dp[node][K]

    # Get the number of children
    nchild = len(graph[node])
    temp = 0

    # Iterate to all the adjacent nodes
    for child in graph[node]:
        # Iterate further in nodes
        temp = (temp + dfs(child, graph, visited, coins, K - 1, dp)) % mod

    # If adjacent nodes are zero
    if nchild == 0:
        temp = coins[node]
    else:
        temp = ((coins[node] * nchild + temp) * powermod(nchild, mod - 2)) % mod

    # Store the coins in dp
    dp[node][K] = temp
    return temp

# Function to find the number of coins we can achieve
def expectedCoins(V, E, a, edges, k):
    # Declare a vector graph
    graph = [[] for _ in range(V)]
    dp = [[-1] * (k + 1) for _ in range(V)]

    # Create an adjacency list
    for e in edges:
        graph[e[0]].append(e[1])
        graph[e[1]].append(e[0])

    # Iterate in vertices
    ans = 0
    for i in range(V):
        # Initialize a vector visited
        visited = [False] * V

        # Call the dfs function
        temp = dfs(i, graph, visited, a, k, dp)

        # Add the number of coins to ans
        ans = (ans + temp) % mod

    if ans % V == 0:
        return (ans // V) % mod
    ans = (ans * powermod(V, mod - 2)) % mod

    return ans

# Driver code
if __name__ == "__main__":
    V = 4
    E = 4
    K = 1
    edges = [[0, 1], [0, 2], [1, 2], [2, 3]]
    coins = [1, 1, 1, 2]

    # Function call
    print(expectedCoins(V, E, coins, edges, K))
    
# This code is contributed by akshitaguprzj3
C#
using System;
using System.Collections.Generic;

class MainClass {
    static int mod = 1000000007; // Modulus value

    // Function to calculate power with modulus
    static long PowerMod(int a, int m) {
        if (a == 0) return 1;
        if (m == 1) return a % mod;

        long temp = PowerMod(a, m / 2) % mod;
        temp = (temp * temp) % mod;

        return m % 2 == 0 ? temp : (a * temp) % mod;
    }

    // Function to perform depth-first search (DFS)
    static int DFS(int node, List<List<int>> graph, List<bool> visited, List<int> coins, int K, List<List<int>> dp) {
        if (K == 0) return coins[node]; // If number of steps becomes 0

        if (dp[node][K] != -1) return dp[node][K]; // If the value for this node and steps has been already calculated

        int nchild = graph[node].Count; // Get the number of children
        int temp = 0;

        // Iterate over all adjacent nodes
        foreach (int child in graph[node]) {
            temp = (temp + DFS(child, graph, visited, coins, K - 1, dp)) % mod; // DFS on child nodes
        }

        if (nchild == 0)
            temp = coins[node]; // If no children, take the coin value of the node
        else
            temp = (int)(((long)(coins[node] * nchild + temp) * PowerMod(nchild, mod - 2)) % mod); // Calculate the expected coins using formula

        dp[node][K] = temp; // Store the result in dp array
        return temp;
    }

    // Function to find the expected number of coins
    static int ExpectedCoins(int V, int E, List<int> a, List<List<int>> edges, int k) {
        List<List<int>> graph = new List<List<int>>(V);
        List<List<int>> dp = new List<List<int>>();
        
        // Initialize graph and dp array
        for (int i = 0; i < V; i++) {
            graph.Add(new List<int>());
            dp.Add(new List<int>());
            for (int j = 0; j <= k; j++) {
                dp[i].Add(-1);
            }
        }

        // Create adjacency list
        foreach (var e in edges) {
            graph[e[0]].Add(e[1]);
            graph[e[1]].Add(e[0]);
        }

        int ans = 0;
        for (int i = 0; i < V; i++) {
            List<bool> visited = new List<bool>(new bool[V]); // Initialize visited array
            int temp = DFS(i, graph, visited, a, k, dp); // Call DFS for each node
            ans = (ans + temp) % mod; // Update the answer
        }

        if (ans % V == 0) return (ans / V) % mod;
        ans = (int)(((long)ans * PowerMod(V, mod - 2)) % mod); // Calculate the final answer using formula

        return ans;
    }

    public static void Main(string[] args) {
        int V = 4;
        int E = 4;
        int K = 1;
        List<List<int>> edges = new List<List<int>>() { new List<int>() { 0, 1 }, new List<int>() { 0, 2 }, new List<int>() { 1, 2 }, new List<int>() { 2, 3 } };
        List<int> coins = new List<int>() { 1, 1, 1, 2 };

        Console.WriteLine(ExpectedCoins(V, E, coins, edges, K)); // Output: 1
    }
}
JavaScript
const mod = 1000000007;

// Function to calculate power with modulus
const powerMod = (a, m) => {
  if (a === 0) return 1;
  if (m === 1) return a % mod;

  let temp = powerMod(a, Math.floor(m / 2)) % mod;
  temp = (temp * temp) % mod;

  return m % 2 === 0 ? temp : (a * temp) % mod;
};

// Function to perform depth-first search (DFS)
const DFS = (node, graph, visited, coins, K, dp) => {
  if (K === 0) return coins[node]; // If number of steps becomes 0

  if (dp[node][K] !== -1) return dp[node][K]; // If the value for this node and steps has been already calculated

  const nchild = graph[node].length; // Get the number of children
  let temp = 0;

  // Iterate over all adjacent nodes
  for (let child of graph[node]) {
    temp = (temp + DFS(child, graph, visited, coins, K - 1, dp)) % mod; // DFS on child nodes
  }

  if (nchild === 0) temp = coins[node]; // If no children, take the coin value of the node
  else temp = (coins[node] * nchild + temp) * powerMod(nchild, mod - 2) % mod; // Calculate the expected coins using formula

  dp[node][K] = temp; // Store the result in dp array
  return temp;
};

// Function to find the expected number of coins
const expectedCoins = (V, E, a, edges, k) => {
  const graph = new Array(V).fill(0).map(() => []);
  const dp = new Array(V).fill(0).map(() => new Array(k + 1).fill(-1));

  // Initialize graph and dp array
  for (let i = 0; i < V; i++) {
    for (let j = 0; j <= k; j++) {
      dp[i][j] = -1;
    }
  }

  // Create adjacency list
  for (let e of edges) {
    graph[e[0]].push(e[1]);
    graph[e[1]].push(e[0]);
  }

  let ans = 0;
  for (let i = 0; i < V; i++) {
    const visited = new Array(V).fill(false); // Initialize visited array
    const temp = DFS(i, graph, visited, a, k, dp); // Call DFS for each node
    ans = (ans + temp) % mod; // Update the answer
  }

  if (ans % V === 0) return (ans / V) % mod;
  ans = (ans * powerMod(V, mod - 2)) % mod; // Calculate the final answer using formula

  return ans;
};

const V = 4;
const E = 4;
const K = 1;
const edges = [[0, 1], [0, 2], [1, 2], [2, 3]];
const coins = [1, 1, 1, 2];

console.log(expectedCoins(V, E, coins, edges, K)); // Output: 1

Output
333333338



Time Complexity: O(V * E), V is the number of nodes and E is the number of edges.
Auxiliary Space: O(V * E)



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads