Cheapest Cost to All Cities - Google Top Interview Questions


Problem Statement :


You are given two lists of integers costs_from and costs_to of the same length where each index i represents a city. 

Building a one-way road from city i to j costs costs_from[i] + costs_to[j]. 

You are also given a two-dimensional list of integers edges where each list contains [x, y] meaning there's already a one-way road from city x to y.

Given that we want to be able to go to any city from city 0 (not necessarily in one path), return the minimum cost to build the necessary roads.

Constraints

n ≤ 1,000 where n is the length of costs_from and costs_to

m ≤ 100,000 where m is the length of edges

Example 1

Input

costs_from = [5, 1, 1, 10]

costs_to = [1, 1, 2, 1]

edges = [

    [0, 3]

]

Output

9

Explanation

We can go 0 to 2 for a cost of 7. Then, we can go 2 to 1 for a cost of 2. We already have the ability to go 
to 3 from 0 for free.



Solution :



title-img




                        Solution in C++ :

const int M = 1000000;
const int N = 1000;

struct edg {
    int u, v;
    int cost;
} E[M], E_copy[M];

int In[N], ID[N], vis[N], pre[N];

int Directed_MST(int root, int NV, int NE) {
    for (int i = 0; i < NE; i++) {
        E_copy[i] = E[i];
    }
    int ret = 0;
    int u, v;
    while (true) {
        for (int i = 0; i < NV; i++) {
            In[i] = 2000000000;
        }
        for (int i = 0; i < NE; i++) {
            u = E_copy[i].u;
            v = E_copy[i].v;
            if (E_copy[i].cost < In[v] && u != v) {
                In[v] = E_copy[i].cost;
                pre[v] = u;
            }
        }

        int cnt = 0;
        for (int i = 0; i < NV; i++) {
            ID[i] = -1;
            vis[i] = -1;
        }
        In[root] = 0;

        // check for cycles
        for (int i = 0; i < NV; i++) {
            ret += In[i];
            int v = i;
            while (vis[v] != i && ID[v] == -1 && v != root) {
                vis[v] = i;
                v = pre[v];
            }
            if (v != root && ID[v] == -1) {
                for (u = pre[v]; u != v; u = pre[u]) {
                    ID[u] = cnt;
                }
                ID[v] = cnt++;
            }
        }
        // check if there are no cycles
        if (cnt == 0) {
            break;
        }

        // condense cycles
        for (int i = 0; i < NV; i++) {
            if (ID[i] == -1) {
                ID[i] = cnt++;
            }
        }
        for (int i = 0; i < NE; i++) {
            v = E_copy[i].v;
            E_copy[i].u = ID[E_copy[i].u];
            E_copy[i].v = ID[E_copy[i].v];
            if (E_copy[i].u != E_copy[i].v) {
                E_copy[i].cost -= In[v];
            }
        }
        NV = cnt;
        root = ID[root];
    }
    return ret;
}

int solve(vector<int>& costs_from, vector<int>& costs_to, vector<vector<int>>& edges) {
    int n = costs_from.size();
    vector<pair<int, int>> v;
    for (auto& e : edges) {
        v.emplace_back(e[0], e[1]);
    }
    sort(v.begin(), v.end());
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            pair<int, int> key = make_pair(i, j);
            auto it = lower_bound(v.begin(), v.end(), key);
            if (it != v.end() && *it == key) {
                E[i * n + j].cost = 0;
            } else {
                E[i * n + j].cost = costs_from[i] + costs_to[j];
            }
            E[i * n + j].u = i;
            E[i * n + j].v = j;
        }
    }
    return Directed_MST(0, n, n * n);
}
                    


                        Solution in Java :

import java.util.*;

class Solution {
    public int solve(int[] costs_from, int[] costs_to, int[][] edges) {
        int n = costs_to.length;
        ArrayList<Integer>[] es = new ArrayList[n];
        int[] rd = new int[n], low = new int[n], st = new int[n], en = new int[n];
        for (int i = 0; i < n; ++i) {
            rd[i] = -1;
            st[i] = costs_from[i];
            en[i] = costs_to[i];
        }
        Arrays.fill(low, n + 1);
        boolean[] path = new boolean[n], seen = new boolean[n];
        for (int[] e : edges) {
            if (es[e[0]] == null)
                es[e[0]] = new ArrayList();
            es[e[0]].add(e[1]);
        }
        int from = mark(es, 0, seen, costs_from), res = 0;
        for (int i = 1; i < n; ++i) {
            if (!seen[i]) {
                ArrayList<Integer> al = new ArrayList();
                int[] ms = new int[1];
                ms[0] = costs_from[i];
                int t = costs_to[i];
                traverse(es, st, rd, 0, low, new Stack<Integer>(), al, i, seen, path, ms, i);
                for (int a : al) {
                    rd[a] = i;
                    st[a] = ms[0];
                    t = Math.min(t, costs_to[a]);
                }
                for (int a : al) {
                    en[a] = t;
                }
            }
        }
        ArrayList<int[]> al = new ArrayList();
        for (int i = 1; i < n; ++i) {
            int t = find(rd, i);
            if (t >= 0) {
                rd[t] = -1;
                al.add(new int[] {st[t], en[t]});
            }
        }
        if (al.size() == 0)
            return 0;
        Collections.sort(al, (a, b) -> (a[0] - b[0]));
        for (int[] d : al) {
            res += from + d[1];
            from = Math.min(from, d[0]);
        }
        return res;
    }
    private int mark(ArrayList<Integer>[] es, int idx, boolean[] seen, int[] fr) {
        seen[idx] = true;
        int res = fr[idx];
        if (es[idx] != null) {
            for (int a : es[idx]) {
                if (!seen[a]) {
                    int t = mark(es, a, seen, fr);
                    res = Math.min(res, t);
                }
            }
        }
        return res;
    }
    private int find(int[] rd, int idx) {
        while (idx >= 0 && idx != rd[idx]) {
            int t = rd[idx];
            if (t >= 0)
                rd[idx] = rd[t];
            idx = rd[idx];
        }
        return idx;
    }
    private void traverse(ArrayList<Integer>[] es, int[] st, int[] rd, int h, int[] low,
        Stack<Integer> sta, ArrayList<Integer> al, int idx, boolean[] seen, boolean[] path,
        int[] ms, int root) {
        seen[idx] = true;
        low[idx] = h;
        path[idx] = true;
        sta.push(idx);
        if (es[idx] != null) {
            for (int a : es[idx]) {
                ms[0] = Math.min(ms[0], st[a]);
                int t = find(rd, a);
                if (t >= 0)
                    rd[t] = -1;
                if (!seen[a]) {
                    traverse(es, st, rd, h + 1, low, sta, al, a, seen, path, ms, root);
                    low[idx] = Math.min(low[idx], low[a]);
                } else if (path[a]) {
                    low[idx] = Math.min(low[idx], low[a]);
                }
            }
        }
        if (low[idx] == h) {
            while (!sta.isEmpty()) {
                int t = sta.pop();
                if (idx == root)
                    al.add(t);
                path[t] = false;
                if (t == idx)
                    break;
            }
        }
    }
}
                    


                        Solution in Python : 
                            
class Solution:
    def solve(self, costs_from, costs_to, edges):
        adj = defaultdict(list)
        for u, v in edges:
            if v != 0:
                adj[u].append(v)

        idx = -1
        start = {}
        lowlink = {}
        s = []
        in_stack = set()
        scc = {}
        root = {}

        def tarjan(v):
            nonlocal idx
            idx += 1
            start[v] = idx
            lowlink[v] = idx
            s.append(v)
            in_stack.add(v)

            for n in adj[v]:
                if n not in start:
                    tarjan(n)
                    lowlink[v] = min(lowlink[v], lowlink[n])
                elif n in in_stack:
                    lowlink[v] = min(lowlink[v], start[n])

            if lowlink[v] == start[v]:
                new_scc = []
                while s[-1] != v:
                    in_stack.remove(s[-1])
                    root[s[-1]] = v
                    new_scc.append(s.pop())

                in_stack.remove(s[-1])
                root[s[-1]] = v
                new_scc.append(s.pop())

                scc[v] = new_scc

        for i in range(len(costs_from)):
            if i not in start:
                tarjan(i)

        new_adj = defaultdict(set)
        new_from = {}
        new_to = {}

        for r in scc:
            to = fr = float("inf")
            for n in scc[r]:
                to = min(to, costs_to[n])
                fr = min(fr, costs_from[n])
                new_adj[r].update(root[k] for k in adj[n])

            new_from[r] = fr
            new_to[r] = to

        visited = set()
        sources = {}

        def dfs(cur):
            m = new_from[cur]
            for n in new_adj[cur]:
                if n in sources:
                    m = min(m, sources[n])
                    del sources[n]
                elif n not in visited:
                    visited.add(n)
                    m = min(m, dfs(n))

            return m

        for v in new_to.keys():
            if v not in visited:
                visited.add(v)
                sources[v] = dfs(v)

        src = min(sources.keys(), key=sources.get)
        res = sources[0] - sources[src]
        for v in sources:
            if v != 0:
                res += sources[src] + new_to[v]

        return res
                    


View More Similar Problems

Inserting a Node Into a Sorted Doubly Linked List

Given a reference to the head of a doubly-linked list and an integer ,data , create a new DoublyLinkedListNode object having data value data and insert it at the proper location to maintain the sort. Example head refers to the list 1 <-> 2 <-> 4 - > NULL. data = 3 Return a reference to the new list: 1 <-> 2 <-> 4 - > NULL , Function Description Complete the sortedInsert function

View Solution →

Reverse a doubly linked list

This challenge is part of a tutorial track by MyCodeSchool Given the pointer to the head node of a doubly linked list, reverse the order of the nodes in place. That is, change the next and prev pointers of the nodes so that the direction of the list is reversed. Return a reference to the head node of the reversed list. Note: The head node might be NULL to indicate that the list is empty.

View Solution →

Tree: Preorder Traversal

Complete the preorder function in the editor below, which has 1 parameter: a pointer to the root of a binary tree. It must print the values in the tree's preorder traversal as a single line of space-separated values. Input Format Our test code passes the root node of a binary tree to the preOrder function. Constraints 1 <= Nodes in the tree <= 500 Output Format Print the tree's

View Solution →

Tree: Postorder Traversal

Complete the postorder function in the editor below. It received 1 parameter: a pointer to the root of a binary tree. It must print the values in the tree's postorder traversal as a single line of space-separated values. Input Format Our test code passes the root node of a binary tree to the postorder function. Constraints 1 <= Nodes in the tree <= 500 Output Format Print the

View Solution →

Tree: Inorder Traversal

In this challenge, you are required to implement inorder traversal of a tree. Complete the inorder function in your editor below, which has 1 parameter: a pointer to the root of a binary tree. It must print the values in the tree's inorder traversal as a single line of space-separated values. Input Format Our hidden tester code passes the root node of a binary tree to your $inOrder* func

View Solution →

Tree: Height of a Binary Tree

The height of a binary tree is the number of edges between the tree's root and its furthest leaf. For example, the following binary tree is of height : image Function Description Complete the getHeight or height function in the editor. It must return the height of a binary tree as an integer. getHeight or height has the following parameter(s): root: a reference to the root of a binary

View Solution →