Day 8: Playground

Megathread guidelines

  • Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
  • You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://topaz.github.io/paste/ if you prefer sending it through a URL

FAQ

  • Avicenna
    link
    fedilink
    arrow-up
    3
    ·
    edit-2
    1 month ago

    I went here for graphs (to find connected components) and binary search (for efficiency)

    #!/usr/bin/env python3
    from pathlib import Path
    
    import numpy as np
    import networkx as nx
    
    cwd = Path(__file__).parent.resolve()
    
    
    def parse_input(file_path):
      with file_path.open("r") as fp:
        coords = list(map(lambda x: list(map(int, x.split(','))), fp.readlines()))
    
      return np.array(coords)
    
    
    def binary_search(G, dist):
    
      Itriu = np.triu_indices(dist.shape[0], k=1)
      dist = dist[Itriu]
    
      components = list(nx.connected_components(G))
      Isort = [(Itriu[0][i], Itriu[1][i]) for i in np.argsort(dist)]
    
      icurrent =  0
      ihist = []
      nhist =  []
    
      while len(ihist)<2 or ihist[-1]!=ihist[-2]:
    
        ihist.append(icurrent)
        G.add_edges_from(Isort[:icurrent])
        components = list(nx.connected_components(G))
        nhist.append(len(components))
    
        G.remove_edges_from(Isort[:icurrent])
    
        if len(components)>1:
          # if >1 component, go between this and closest next index with 1 component
          I = [ind for ind,n in enumerate(nhist) if n==1]
    
          if len(I)==0:
            inext = len(Isort)
          else:
            inext = min(np.array(ihist)[I])
    
          icurrent = icurrent + int(np.ceil((inext-icurrent)/2))
    
        else: 
          # if 1 component, go between nearest previous >1 components and this index
          I = [ind for ind,n in enumerate(nhist) if n>1]
    
          if len(I)==0:
            iprev = 0
          else:
            iprev = max(np.array(ihist)[I])
    
          icurrent = iprev + int(np.ceil((icurrent-iprev)/2))
    
      return Isort[icurrent-1]
    
    
    def solve_problem(file_name, nconnect):
    
      coordinates = parse_input(Path(cwd, file_name))
      G = nx.Graph()
      G.add_nodes_from(range(coordinates.shape[0]))
    
      dist = np.sqrt(np.sum((coordinates[None,:] - coordinates[:,None])**2,
                            axis=-1))
    
      if nconnect != -1: # part 1
        Itriu = np.triu_indices(dist.shape[0], k=1)
        dist = dist[Itriu]
        Isort = [(Itriu[0][i], Itriu[1][i]) for i in np.argsort(dist)[:nconnect]]
    
        G.add_edges_from(Isort)
        components = sorted(list(nx.connected_components(G)), key=len)[::-1]
    
        return np.prod(list(map(len, components[:3])))
      else: # part 2
        indices = binary_search(G, dist)
        return np.prod(coordinates[indices,:],axis=0)[0]
    
    
    if __name__ == "__main__":
    
      assert solve_problem("test_input", 10) == 40
      assert solve_problem("input", 1000) == 115885
      assert solve_problem("test_input", -1) == 25272
      assert solve_problem("input", -1) == 274150525