let libs = [
  ("des_system_lib", ["std", "synopsys", "std_cell_lib", "des_system_lib", "dw02", "dw01", "ramlib", "ieee"]),
  ("dw01", ["ieee", "dw01", "dware", "gtech"]),
  ("dw02", ["ieee", "dw02", "dware"]),
  ("dw03", ["std", "synopsys", "dware", "dw03", "dw02", "dw01", "ieee", "gtech"]),
  ("dw04", ["dw04", "ieee", "dw01", "dware", "gtech"]),
  ("dw05", ["dw05", "ieee", "dware"]),
  ("dw06", ["dw06", "ieee", "dware"]),
  ("dw07", ["ieee", "dware"]),
  ("dware", ["ieee", "dware"]),
  ("gtech", ["ieee", "gtech"]),
  ("ramlib", ["std", "ieee"]),
  ("std_cell_lib", ["ieee", "std_cell_lib"]),
  ("synopsys", [])
]

struct Library {
  var name: String
  var children: [String]
  var numParents: Int
}

func buildLibraries(_ input: [(String, [String])]) -> [String: Library] {
  var libraries = [String: Library]()

  for (name, parents) in input {
    var numParents = 0

    for parent in parents where parent!= name {
      numParents += 1

      libraries[parent, default: Library(name: parent, children: [], numParents: 0)].children.append(name)
    }

    libraries[name, default: Library(name: name, children: [], numParents: numParents)].numParents = numParents
  }

  return libraries
}

func topologicalSort(libs: [String: Library]) -> [String]? {
  var libs = libs
  var needsProcessing = Set(libs.keys)
  var options = libs.compactMap({ $0.value.numParents == 0? $0.key: nil })
  var sorted = [String]()

  while let cur = options.popLast() {
    for children in libs[cur]?.children?? [] {
      libs[children]?.numParents -= 1

      if libs[children]?.numParents == 0 {
        options.append(libs[children]!.name)
      }
    }

    libs[cur]?.children.removeAll()

    sorted.append(cur)
    needsProcessing.remove(cur)
  }

  guard needsProcessing.isEmpty else {
    return nil
  }

  return sorted
}

print(topologicalSort(libs: buildLibraries(libs))!)