Problem:
Problem 08: Provident Housewife

主婦の琴子はこの不況のさなか食費を抑えることに闘志を燃やしていました。毎朝新聞広告を必ずチェック。買う物リストと最も安く売られているお店をしっかりリストアップして、お店をはしごしながら、エプロン・サンダルという戦闘スタイルで自転車をこぎこぎ買い物に行きます。

そこで夫のあなたは少しでも琴子の役に立とうと、得意のプログラミングで家計簿プログラムを作成することにしました。プログラムは、各スーパーに売っている品物の名前と値段（円）、琴子が必要な品物を入力し、全ての品物を集めるための最小金額を出力します。

琴子は家を出て必要な品物を集め、家に戻ってこなければなりません。
そこで、琴子を気遣ったあなたは、最小金額が同じになる買い物ルートが複数ある場合も考慮して、より距離が短くなるルートの距離を報告する機能を追加することにしました。従って、プログラムはスーパー・家間を繋ぐ道の情報も入力します。

スーパーの数を n とし、各スーパーにはそれぞれ 1 から n までの番号が割り当てられます。さらに琴子の家を 0 番とします。道の情報はこれらの番号のペアとその距離（整数）で与えられます。

Input

入力として複数のデータセットが与えられます。各データセットの形式は以下の通りです：

n　（スーパーの数：整数）

k1 name1 value1 name2 value2 . . . namek1 valuek1（1 番目のスーパーにある品物の種類の数、1つ目の品物名と値段、2つ目の品物名と値段,,,：整数と文字列の空白区切り）

k2 name1 value1 name2 value2 . . . namek2 valuek2（2 番目のスーパーにある品物の種類の数、1つ目の品物名と値段、2つ目の品物名と値段,,,：整数と文字列の空白区切り）

.

.

kn name1 value1 name2 value2 . . . namekn valuekn（n 番目のスーパーにある品物の種類の数、1つ目の品物名と値段、2つ目の品物名と値段,,,：整数と文字列の空白区切り）

q　（必要な品物の数：整数）

name1　（1 つ目の必要な品物の名前：文字列）

name2　（2 つ目の必要な品物の名前：文字列）

.

.

nameq　（q つ目の必要な品物の名前：文字列）

m　（道の数：整数）

s1 t1 d1　（1 本目の道の情報：空白区切りの整数）

s2 t2 d2　（2 本目の道の情報：空白区切りの整数）

.

.

sm tm dm　（m 本目の道の情報：空白区切りの整数）

si ti di は si番目のスーパー（または家）と ti番目のスーパー（または家）が双方向に行き来することができ、その距離が diであることを示します。

家から（スーパーを経由して）全てのスーパーへ行くことができるような道が与えられます。

n は 10 以下であり、q は 15 以下とします。
ki は 100 以下であり、
品物名の文字列は 20文字を越ず、品物の値段は 10000 を越えません。
また、道の長さは 1000 を越えません。

n が 0 のとき、入力の終わりとします。

Output

各データセットについて、最小の金額と距離を１つの空白で区切って１行に出力して下さい。ただし、必要な品物を全て集められない場合は "impossible" と出力して下さい。

Sample Input

3
3 apple 100 banana 200 egg 300
3 apple 150 banana 100 cola 200
3 apple 100 banana 150 cola 200
3
apple
banana
cola
5
0 2 4
0 1 3
0 3 3
1 2 3
2 3 5
3
3 apple 100 banana 200 egg 300
3 apple 150 banana 100 cola 200
3 apple 100 banana 150 cola 200
4
apple
banana
cola
jump
5
0 2 4
0 1 3
0 3 3
1 2 3
2 3 5
0

Output for the Sample Input

400 10
impossible

Solution in Scala (judge verdict: Accepted)

import scala.collection.mutable

object Main extends App {

  import scala.io.StdIn._
  import scala.math._
  solve
  def solve:Unit = {
    val n = readLine.trim.toInt
    if (n == 0) return
    val stores = Array.tabulate(n) { _ ⇒
      val goods = readLine.trim.split(' ')
      (1 until goods.size by 2).map { it ⇒ (goods(it), goods(it + 1).toInt) }.toMap
    }
    val q = readLine.trim.toInt
    val needs = Array.tabulate(q) { _ ⇒ readLine.trim }
    val storesWithCanBuy = Array.tabulate(n + 1) { _ ⇒ 0 }
    var sum: Option[Int] = Some(0)
    for ((name, i) ← needs.zipWithIndex) {
      val prices = stores.zipWithIndex.flatMap { case (m, id) ⇒ m.get(name).map{(_, id)}}
      if (sum.isEmpty || prices.length == 0) {
        sum = None
      } else {
        val min = prices.map(_._1).min
        sum = sum.map {
          _ + min
        }
        for (s ← prices.withFilter(_._1 == min).map(_._2)) {
          storesWithCanBuy(s + 1) += 1 << i
        }
      }
    }
    val minRoute = Array.tabulate(n + 1) { f ⇒ Array.tabulate(n + 1) { t ⇒ if (f != t) Int.MaxValue else 0: Int } }
    for (_ ← 0 until readLine.trim.toInt) {
      val Array(s, t, d) = readLine.trim.split(' ').map(_.toInt)
      minRoute(s)(t) = d
      minRoute(t)(s) = d
    }
    for {k ← 0 to n
         i ← 0 to n
         j ← 0 to n} {
      if (minRoute(i)(j) - minRoute(i)(k) > minRoute(k)(j)) {
        minRoute(i)(j) = minRoute(i)(k) + minRoute(k)(j)
      }
    }
    val minMemo = Array.tabulate(n + 1) { _ ⇒ Array.tabulate(1 << q) { _ ⇒ Int.MaxValue } }.also(a ⇒ a(0)(0) = 0)
    val queue = mutable.PriorityQueue()(Ordering.by[(Int, Int, Int), Int](_._3).reverse).also(a ⇒ a.enqueue((0, 0, 0)))
    while (queue.nonEmpty) {
      val (current, goods, distance) = queue.dequeue()
      if (minMemo(current)(goods) == distance) {
        for (i ← 0 to n) {
          if (minMemo(i)(goods | storesWithCanBuy(i)) - distance > minRoute(i)(current)) {
            minMemo(i)(goods | storesWithCanBuy(i)) = minRoute(i)(current) + distance
            queue.enqueue((i, goods | storesWithCanBuy(i), minMemo(i)(goods | storesWithCanBuy(i))))
          }
        }
      }
    }
    println(
      sum match {
        case Some(s) ⇒ s"$s ${ minMemo(0).last }"
        case None ⇒ "impossible"
      }
    )
    solve
  }
  implicit class Extension[T](val value :T){
    def also(func: T ⇒ Unit): T = {
      func(value)
      value
    }
    def let[R](func: T ⇒ R): R = func(value)
  }
}