diff --git a/src/main/kotlin/g1601_1700/s1659_maximize_grid_happiness/Solution.kt b/src/main/kotlin/g1601_1700/s1659_maximize_grid_happiness/Solution.kt index 6a03427c7..200825b16 100644 --- a/src/main/kotlin/g1601_1700/s1659_maximize_grid_happiness/Solution.kt +++ b/src/main/kotlin/g1601_1700/s1659_maximize_grid_happiness/Solution.kt @@ -1,80 +1,112 @@ package g1601_1700.s1659_maximize_grid_happiness // #Hard #Dynamic_Programming #Bit_Manipulation #Bitmask #Memoization -// #2023_06_15_Time_181_ms_(100.00%)_Space_36.9_MB_(100.00%) +// #2025_04_04_Time_44_ms_(100.00%)_Space_56.67_MB_(100.00%) -class Solution { - private var m = 0 - private var n = 0 - private lateinit var dp: Array>>> - private val notPlace = 0 - private val intro = 1 - private val extro = 2 - private var mod = 0 +import kotlin.math.max - fun getMaxGridHappiness(m: Int, n: Int, introvertsCount: Int, extrovertsCount: Int): Int { - this.m = m - this.n = n - val numOfState = Math.pow(3.0, n.toDouble()).toInt() - dp = Array(m) { - Array(n) { - Array(introvertsCount + 1) { - Array(extrovertsCount + 1) { IntArray(numOfState) } - } - } +@Suppress("kotlin:S107") +class Solution { + private fun maxHappiness( + index: Int, + m: Int, + n: Int, + introverts: Int, + extroverts: Int, + board: Int, + dp: Array>>, + tmask: Int, + ): Int { + if (index >= m * n) { + return 0 + } + if (dp[index][introverts][extroverts][board] != 0) { + return dp[index][introverts][extroverts][board] + } + var introScore = -1 + var extroScore = -1 + if (introverts > 0) { + val newBoard = ((board shl 2) or INTROVERT) and tmask + introScore = + ( + 120 + + adjust(board, INTROVERT, n, index) + + maxHappiness( + index + 1, + m, + n, + introverts - 1, + extroverts, + newBoard, + dp, + tmask, + ) + ) + } + if (extroverts > 0) { + val newBoard = ((board shl 2) or EXTROVERT) and tmask + extroScore = + ( + 40 + + adjust(board, EXTROVERT, n, index) + + maxHappiness( + index + 1, + m, + n, + introverts, + extroverts - 1, + newBoard, + dp, + tmask, + ) + ) } - mod = numOfState / 3 - return dfs(0, 0, introvertsCount, extrovertsCount, 0) + val newBoard = ((board shl 2) or NONE) and tmask + val skip = maxHappiness(index + 1, m, n, introverts, extroverts, newBoard, dp, tmask) + dp[index][introverts][extroverts][board] = + max(skip, max(introScore, extroScore)) + return dp[index][introverts][extroverts][board] } - private fun dfs(x: Int, y: Int, ic: Int, ec: Int, state: Int): Int { - if (x == m) { - return 0 - } else if (y == n) { - return dfs(x + 1, 0, ic, ec, state) - } - if (dp[x][y][ic][ec][state] != 0) { - return dp[x][y][ic][ec][state] + private fun adjust(board: Int, thisIs: Int, col: Int, index: Int): Int { + val shiftBy = 2 * (col - 1) + var left = board and 0x03 + if (index % col == 0) { + left = NONE } - // 1 - not place - var max = dfs(x, y + 1, ic, ec, state % mod * 3) - val up = state / mod - val left = state % 3 - // 2 - place intro - if (ic > 0) { - var temp = 120 - if (x > 0 && up != notPlace) { - temp -= 30 - temp += if (up == intro) -30 else 20 + val up = (board shr shiftBy) and 0x03 + val combination = intArrayOf(left, up) + var adjustment = 0 + for (neighbor in combination) { + if (neighbor == NONE) { + continue } - if (y > 0 && left != notPlace) { - temp -= 30 - temp += if (left == intro) -30 else 20 + if (neighbor == INTROVERT && thisIs == INTROVERT) { + adjustment -= 60 + } else if (neighbor == INTROVERT && thisIs == EXTROVERT) { + adjustment -= 10 + } else if (neighbor == EXTROVERT && thisIs == INTROVERT) { + adjustment -= 10 + } else if (neighbor == EXTROVERT && thisIs == EXTROVERT) { + adjustment += 40 } - var nextState = state - nextState %= mod - nextState *= 3 - nextState += intro - max = Math.max(max, temp + dfs(x, y + 1, ic - 1, ec, nextState)) } - // 3 - place extro - if (ec > 0) { - var temp = 40 - if (x > 0 && up != notPlace) { - temp += 20 - temp += if (up == intro) -30 else 20 - } - if (y > 0 && left != notPlace) { - temp += 20 - temp += if (left == intro) -30 else 20 + return adjustment + } + + fun getMaxGridHappiness(m: Int, n: Int, introvertsCount: Int, extrovertsCount: Int): Int { + val dp = Array>>(m * n) { + Array>(introvertsCount + 1) { + Array(extrovertsCount + 1) { IntArray((1 shl (2 * n))) } } - var nextState = state - nextState %= mod - nextState *= 3 - nextState += extro - max = Math.max(max, temp + dfs(x, y + 1, ic, ec - 1, nextState)) } - dp[x][y][ic][ec][state] = max - return max + val tmask = (1 shl (2 * n)) - 1 + return maxHappiness(0, m, n, introvertsCount, extrovertsCount, 0, dp, tmask) + } + + companion object { + private const val NONE = 0 + private const val INTROVERT = 1 + private const val EXTROVERT = 2 } } diff --git a/src/main/kotlin/g3401_3500/s3435_frequencies_of_shortest_supersequences/Solution.kt b/src/main/kotlin/g3401_3500/s3435_frequencies_of_shortest_supersequences/Solution.kt index 08c527ff3..82250481d 100644 --- a/src/main/kotlin/g3401_3500/s3435_frequencies_of_shortest_supersequences/Solution.kt +++ b/src/main/kotlin/g3401_3500/s3435_frequencies_of_shortest_supersequences/Solution.kt @@ -1,103 +1,106 @@ package g3401_3500.s3435_frequencies_of_shortest_supersequences // #Hard #Array #String #Bit_Manipulation #Graph #Enumeration #Topological_Sort -// #2025_01_29_Time_35_ms_(100.00%)_Space_43.62_MB_(100.00%) +// #2025_04_04_Time_275_ms_(100.00%)_Space_49.81_MB_(100.00%) class Solution { - private var m = 0 - private var forcedMask = 0 - private lateinit var adj: IntArray - private val idxToChar = CharArray(26) - private val charToIdx = IntArray(26) - private val used = BooleanArray(26) + private var min = Int.Companion.MAX_VALUE + private var lists: MutableList = ArrayList() fun supersequences(words: Array): List> { - charToIdx.fill(-1) - for (w in words) { - used[w[0].code - 'a'.code] = true - used[w[1].code - 'a'.code] = true + val pairs = Array(26) { BooleanArray(26) } + val counts = IntArray(26) + for (word in words) { + val a = word[0].code - 'a'.code + val b = word[1].code - 'a'.code + if (!pairs[a][b]) { + pairs[a][b] = true + counts[a]++ + counts[b]++ + } } - // Map each used letter to an index [0..m-1] - for (c in 0..25) { - if (used[c]) { - idxToChar[m] = (c + 'a'.code).toChar() - charToIdx[c] = m++ + val links: Array> = Array>(26) { ArrayList() } + val counts1 = IntArray(26) + val sides = IntArray(26) + for (i in 0..25) { + for (j in 0..25) { + if (pairs[i][j]) { + links[i].add(j) + counts1[j]++ + sides[i] = sides[i] or 1 + sides[j] = sides[j] or 2 + } } } - adj = IntArray(m) - // Build graph and record forced duplicates - for (w in words) { - val u = charToIdx[w[0].code - 'a'.code] - val v = charToIdx[w[1].code - 'a'.code] - if (u == v) { - forcedMask = forcedMask or (1 shl u) + val arr = IntArray(26) + for (i in 0..25) { + if (counts[i] <= 1) { + arr[i] = counts[i] + } else if (counts1[i] == 0 || sides[i] != 3) { + arr[i] = 1 + } else if (pairs[i][i]) { + arr[i] = 2 } else { - adj[u] = adj[u] or (1 shl v) + arr[i] = -1 } } - // Try all supersets of forcedMask; keep those that kill all cycles - var best = 9999 - val goodSets: MutableList = ArrayList() - for (s in 0..<(1 shl m)) { - if ((s and forcedMask) != forcedMask) { - continue - } - val size = Integer.bitCount(s) - if (size <= best && !hasCycle(s)) { - if (size < best) { - best = size - goodSets.clear() - } - goodSets.add(s) + dfs(links, 0, arr, IntArray(26), 0) + val res: MutableList> = ArrayList>() + for (arr1 in lists) { + val list: MutableList = ArrayList() + for (n in arr1) { + list.add(n) } + res.add(list) + } + return res + } + + private fun dfs(links: Array>, i: Int, arr1: IntArray, arr: IntArray, n: Int) { + if (n > min) { + return } - // Build distinct freq arrays from these sets - val seen: MutableSet = HashSet() - val ans: MutableList> = ArrayList>() - for (s in goodSets) { - val freq = IntArray(26) - for (i in 0.. = ArrayList() - for (f in freq) { - tmp.add(f) - } - ans.add(tmp) + if (n < min) { + min = n + lists = ArrayList() + lists.add(arr.clone()) + } else if (n == min) { + lists.add(arr.clone()) } + return + } + if (arr1[i] >= 0) { + arr[i] = arr1[i] + dfs(links, i + 1, arr1, arr, n + arr1[i]) + } else { + arr[i] = 1 + dfs(links, i + 1, arr1, arr, n + 1) + arr[i] = 2 + dfs(links, i + 1, arr1, arr, n + 2) } - return ans } - private fun hasCycle(mask: Int): Boolean { - val color = IntArray(m) - for (i in 0..>, arr: IntArray): Boolean { + for (i in 0..25) { + if (arr[i] == 1 && dfs1(links, arr, BooleanArray(26), i)) { + return false } } - return false + return true } - private fun dfs(u: Int, color: IntArray, mask: Int): Boolean { - color[u] = 1 - var nxt = adj[u] - while (nxt != 0) { - val v = Integer.numberOfTrailingZeros(nxt) - nxt = nxt and (nxt - 1) - if (((mask shr v) and 1) == 1) { - continue - } - if (color[v] == 1) { - return true - } - if (color[v] == 0 && dfs(v, color, mask)) { + private fun dfs1(links: Array>, arr: IntArray, seens: BooleanArray, i: Int): Boolean { + seens[i] = true + for (next in links[i]) { + if (arr[next] == 1 && (seens[next] || dfs1(links, arr, seens, next))) { return true } } - color[u] = 2 + seens[i] = false return false } } diff --git a/src/test/kotlin/g3401_3500/s3435_frequencies_of_shortest_supersequences/SolutionTest.kt b/src/test/kotlin/g3401_3500/s3435_frequencies_of_shortest_supersequences/SolutionTest.kt index abf168d0b..23cd46e99 100644 --- a/src/test/kotlin/g3401_3500/s3435_frequencies_of_shortest_supersequences/SolutionTest.kt +++ b/src/test/kotlin/g3401_3500/s3435_frequencies_of_shortest_supersequences/SolutionTest.kt @@ -12,11 +12,11 @@ internal class SolutionTest { equalTo( listOf( listOf( - 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ), listOf( - 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ), ),