TopCoder ImportsList - TC SRM 447 D2 900


https://community.topcoder.com/stat?c=problem_statement&pm=10579
Every big project contains multiple scripts, each of which may require access to other scripts within the project. Each script contains an import list containing zero or more other scripts. A script has access to all the scripts in its import list, and it also has access to all the scripts that the scripts in its import list have access to. More formally, a script A has access to a script B if and only if there exists a sequence of scripts S[0] = A, S[1], ..., S[k] = B, where k >= 1 and for each i, where 0 <= i < k, script S[i] contains script S[i+1] in its import list. There is an important restriction on the usage of import lists: a script must not have access to itself.

You are given the requirements for your project as a String[] requires. It contains exactly N elements, where N is the number of scripts in the project. Character j of element i of requires is 'Y' if script i must have access to script j, and 'N' otherwise. You must generate the import list for each script in such a way that all the requirements are satisfied. This means that each script must have access to all its required scripts, and not have access to unrequired scripts (including itself). The total number of scripts in all the import lists of all the scripts must be as small as possible (if several import lists contain the same script, each occurrence of that script counts toward the total). Return a int[] containing exactly N elements, where element i is the number of scripts in the import list for script i.

Definition

    
Class:ImportsList
Method:importsCount
Parameters:String[]
Returns:int[]
Method signature:int[] importsCount(String[] requires)
(be sure your method is public)
    

Notes

-Under the given constraints, there always exists exactly one way to generate import lists with the smallest total number of scripts.

Constraints

-requires will contain between 1 and 50 elements, inclusive.
-Each element of requires will contain exactly N characters 'Y' or 'N', where N is the number of elements in requires.
-If the j-th character in the i-th element of requires is 'Y' and the k-th character in the j-th element of requires is 'Y', then the k-th character in the i-th element of requires will be 'Y'.
-The i-th character in i-th element of requires will be 'N'.

Examples

0)
    
{"NNN"
,"NNN"
,"NNN"}
Returns: {0, 0, 0 }
None of these scripts require other scripts, so no imports are needed.
1)
    
{"NYYY"
,"NNYY"
,"NNNY"
,"NNNN"}
Returns: {1, 1, 1, 0 }
Each script needs to import the next one.
2)
    
{"NNNNY"
,"NNNNY"
,"YNNNY"
,"NNNNN"
,"NNNNN"}
Returns: {1, 1, 1, 0, 0 }
Script 2 must import script 0 and each of the scripts 0 and 1 must import script 4.
3)
    
{"NYYNYNYYYNYYNYNN"
,"NNNNNNNNNNNNNNNN"
,"NNNNNNNNNNYNNNNN"
,"NNNNNNNNNYNNYNNN"
,"NYNNNNYNNNYYNNNN"
,"NYNNYNYNYNYYNNNN"
,"NNNNNNNNNNYNNNNN"
,"NNYNNNYNYNYNNNNN"
,"NNNNNNYNNNYNNNNN"
,"NNNNNNNNNNNNYNNN"
,"NNNNNNNNNNNNNNNN"
,"NNNNNNNNNNNNNNNN"
,"NNNNNNNNNNNNNNNN"
,"NNNNNNYNNNYNNNNN"
,"YYYYYNYYYYYYYYNY"
,"NYYYNNYNNYYNYYNN"}
Returns: {3, 0, 1, 1, 3, 2, 1, 2, 1, 1, 0, 0, 0, 1, 2, 4 }

This problem statement is the exclusive and proprietary property of TopCoder, Inc. Any unauthorized use or reproduction of this information without the prior written consent of TopCoder, Inc. is strictly prohibited. (c)2010, TopCoder, Inc. All rights reserved.

https://apps.topcoder.com/forums/?module=Thread&threadID=671561&start=0
The basic observation required is that if A needs access to B, and B needs access to C, then there is no need for A to import C since it will automatically get access via B. Thus, the modules that A must import are those it needs access to, minus those it will get access to through its dependencies.

public class ImportsList
{
    public int[] importsCount(String[] requires)
    {
        int N = requires.length;
        long[] reqMasks = new long[N];
        for (int i = 0; i < N; i++)
            for (int j = 0; j < N; j++)
                if (requires[i].charAt(j) == 'Y')
                    reqMasks[i] |= 1 << j;
 
        int[] ans = new int[N];
        for (int i = 0; i < N; i++)
        {
            long impMask = reqMasks[i];
            for (int j = 0; j < N; j++)
                if ((reqMasks[i] & (1 << j)) != 0)
                    impMask &= ~reqMasks[j];
            ans[i] = Long.bitCount(impMask);
        }
        return ans;
    }
}
This problem asks us to calculate the minimum number of scripts to be used within an import list. For a given script A, it needs access to a set of scripts S1, S2, ..., Sn. The relationships are transitive, so if script A has access to script B and script B has access to script C then script A also has access to script C. We must choose a combination such that a given script has access to all its required scripts whilst also choosing the minimum number of scripts to be imported.

The first observation to make is that the graph is directed, so access does not flow both ways. In fact, given the current constraints there are no cycles in the graph hence we have a directed acyclic graph (DAG). This gives us a huge hint to topologically sort (or linearise) the graph before doing further operations. A topological sort can be achieved with a simple DFS and recording the finished nodes in reverse order. Alright let's assume we now have a linearised DAG - how do we choose the minimum amount? Recall that for an DAG we can order the vertices such that all edges go from left to right. Therefore for a vertex V, we can greedily consider vertices from left to right and keeping track of which vertices can be accessed if we access vertex W.

This works for several reasons. Let's consider two vertices: W and X. Let's say that vertex X is to the right of vertex W. If vertex X is reachable from vertex W then vertex W can access at least as much as vertex X since we can simply access vertex X from W using an arbitrary set of traversals. Let's say that vertex X is not reachable from vertex W, then there could be some scripts which we can access between vertex W and X which we need to fulfill the requirements. If there isn't, then we can simply not use vertex W and we will consider vertex X eventually. Therefore, the optimality follows through the linearised order since we consider the largest set and choosing so does not cause conflicts later on. 

A very simple way to represent what is accessible from a given vertex is to use a bitmask. 



void dfs(int node) {
  if (visited[node]) { if (visited[node] == 1) cycleDetect = 1; return; }
  visited[node] = 1;
  for (int i = 0; i < N; i++) {
    if (adjmat[node][i]) {
      dfs(i);
    }
  } 
  visited[node] = 2;
  order[dfsIdx] = node;
  dfsIdx--;
}

long long mask[N];
long long procMask[N];

vector <int> ImportsList::importsCount(vector <string> requires) {
  vector<int> res(requires.size(),0);
  for (int i = 0; i < requires.size(); i++) {
    long long m = 0;
    for (int j = 0; j < requires.size(); j++) {
      if (requires[i][j] == 'Y') { adjmat[i][j] = 1; m += (1LL << j); }
    }
    mask[i] = m;
  }
  dfsIdx = requires.size()-1;
  for (int i = 0; i < requires.size(); i++) {
    if (!visited[i]) {
      dfs(i);
    }
  }
  // greedy based on topological sorting
  for (int i = requires.size()-1; i >= 0; i--) {
    long long m = mask[order[i]];
    long long p = m;
    int num = 0;
    for (int j = i+1; j < requires.size() && m != 0; j++) {
      if (adjmat[order[i]][order[j]] && (m & (1LL << order[j]))) {
        num++;
        p |= procMask[order[j]];
        m = m & ~(procMask[orderj]]);
      }
    }
    procMask[order[i]] = p;
    res[order[i]] = num;
  }
  return res;
}



Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts