G - Goin' to the Zoo 解説 by cirno3153

実装例

各要素について \(0, 1, 2\) という多値を取る時は、再帰で実装すると楽に書けます。
計算量は \(O(3^NM)\) です。

import java.util.Scanner
import kotlin.math.min
import kotlin.Int
fun main() {
  Scanner(System.`in`).use { sc -> 
    val N = sc.nextInt()
    val M = sc.nextInt()
    val C = IntArray(N) { sc.nextInt() }
    val zoo = Array(N) {MutableList<Int>(0){0}} // 各動物園が持つ動物のリスト
    for (i in 0 until M) {
      var A = IntArray(sc.nextInt()) {sc.nextInt()}
      for (j in A) zoo[j - 1].add(i)
    }
    var watched = IntArray(M) { 0 } // 各動物を見た回数
    println(dfs(0, watched, C, zoo, 0))
  }
}

fun dfs(i: Int, watched: IntArray, C: IntArray, zoo: Array<MutableList<Int>>, ans: Long): Long {
  if (i == C.size) { // 再帰の終了条件
    for (j in watched) {
      if (j < 2) return Long.MAX_VALUE // ある動物について一度以下しか見ていない時は、適当に答えになり得ない値を返す
    }
    return ans
  }
  var ret = dfs(i + 1, watched, C, zoo, ans) // i番目の動物園を訪れない
  for (j in zoo[i]) watched[j]++
  ret = min(ret, dfs(i + 1, watched, C, zoo, ans + C[i])) // i番目の動物園を一度訪れる
  for (j in zoo[i]) watched[j]++
  ret = min(ret, dfs(i + 1, watched, C, zoo, ans + C[i] * 2)) // i番目の動物園を二度訪れる
  for (j in zoo[i]) watched[j] -= 2
  return ret
}

投稿日時:
最終更新: