diff --git a/src/main/java/g1601_1700/s1659_maximize_grid_happiness/Solution.java b/src/main/java/g1601_1700/s1659_maximize_grid_happiness/Solution.java index f10850cc8..fe6561f40 100644 --- a/src/main/java/g1601_1700/s1659_maximize_grid_happiness/Solution.java +++ b/src/main/java/g1601_1700/s1659_maximize_grid_happiness/Solution.java @@ -1,74 +1,96 @@ package g1601_1700.s1659_maximize_grid_happiness; // #Hard #Dynamic_Programming #Bit_Manipulation #Bitmask #Memoization -// #2022_04_23_Time_95_ms_(75.00%)_Space_53.1_MB_(58.33%) +// #2025_04_04_Time_39_ms_(86.36%)_Space_54.76_MB_(72.73%) +@SuppressWarnings("java:S107") public class Solution { - private int m; - private int n; - private int[][][][][] dp; - private int notPlace = 0; - private int intro = 1; - private int extro = 2; - private int mod; + private static final int NONE = 0; + private static final int INTROVERT = 1; + private static final int EXTROVERT = 2; - public int getMaxGridHappiness(int m, int n, int introvertsCount, int extrovertsCount) { - this.m = m; - this.n = n; - int numOfState = (int) Math.pow(3, n); - this.dp = new int[m][n][introvertsCount + 1][extrovertsCount + 1][numOfState]; - this.mod = numOfState / 3; - return dfs(0, 0, introvertsCount, extrovertsCount, 0); - } - - private int dfs(int x, int y, int ic, int ec, int state) { - if (x == m) { + private int maxHappiness( + int index, + int m, + int n, + int introverts, + int extroverts, + int board, + int[][][][] dp, + int tmask) { + if (index >= m * n) { 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]; + if (dp[index][introverts][extroverts][board] != 0) { + return dp[index][introverts][extroverts][board]; } - // 1 - not place - int max = dfs(x, y + 1, ic, ec, (state % mod) * 3); - int up = state / mod; - int left = state % 3; - // 2 - place intro - if (ic > 0) { - int temp = 120; - if (x > 0 && up != notPlace) { - temp -= 30; - temp += up == intro ? -30 : 20; - } - if (y > 0 && left != notPlace) { - temp -= 30; - temp += left == intro ? -30 : 20; - } - int nextState = state; - nextState %= mod; - nextState *= 3; - nextState += intro; - max = Math.max(max, temp + dfs(x, y + 1, ic - 1, ec, nextState)); + int introScore = -1; + int extroScore = -1; + if (introverts > 0) { + int newBoard = ((board << 2) | INTROVERT) & tmask; + introScore = + 120 + + adjust(board, INTROVERT, n, index) + + maxHappiness( + index + 1, + m, + n, + introverts - 1, + extroverts, + newBoard, + dp, + tmask); + } + if (extroverts > 0) { + int newBoard = ((board << 2) | EXTROVERT) & tmask; + extroScore = + 40 + + adjust(board, EXTROVERT, n, index) + + maxHappiness( + index + 1, + m, + n, + introverts, + extroverts - 1, + newBoard, + dp, + tmask); } - // 3 - place extro - if (ec > 0) { - int temp = 40; - if (x > 0 && up != notPlace) { - temp += 20; - temp += up == intro ? -30 : 20; + int newBoard = ((board << 2) | NONE) & tmask; + int skip = maxHappiness(index + 1, m, n, introverts, extroverts, newBoard, dp, tmask); + dp[index][introverts][extroverts][board] = Math.max(skip, Math.max(introScore, extroScore)); + return dp[index][introverts][extroverts][board]; + } + + private int adjust(int board, int thisIs, int col, int index) { + int shiftBy = 2 * (col - 1); + int left = board & 0x03; + if (index % col == 0) { + left = NONE; + } + int up = (board >> shiftBy) & 0x03; + int[] combination = new int[] {left, up}; + int adjustment = 0; + for (int neighbor : combination) { + if (neighbor == NONE) { + continue; } - if (y > 0 && left != notPlace) { - temp += 20; - temp += left == intro ? -30 : 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; } - int 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; + return adjustment; + } + + public int getMaxGridHappiness(int m, int n, int introvertsCount, int extrovertsCount) { + int[][][][] dp = new int[m * n][introvertsCount + 1][extrovertsCount + 1][(1 << (2 * n))]; + int tmask = (1 << (2 * n)) - 1; + return maxHappiness(0, m, n, introvertsCount, extrovertsCount, 0, dp, tmask); } } diff --git a/src/main/java/g3401_3500/s3435_frequencies_of_shortest_supersequences/Solution.java b/src/main/java/g3401_3500/s3435_frequencies_of_shortest_supersequences/Solution.java index dbf3de656..a873a3e88 100644 --- a/src/main/java/g3401_3500/s3435_frequencies_of_shortest_supersequences/Solution.java +++ b/src/main/java/g3401_3500/s3435_frequencies_of_shortest_supersequences/Solution.java @@ -1,109 +1,113 @@ package g3401_3500.s3435_frequencies_of_shortest_supersequences; // #Hard #Array #String #Bit_Manipulation #Graph #Enumeration #Topological_Sort -// #2025_01_29_Time_16_ms_(95.35%)_Space_45.52_MB_(93.02%) +// #2025_04_04_Time_20_ms_(97.26%)_Space_45.52_MB_(83.56%) import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; import java.util.List; -import java.util.Set; +@SuppressWarnings("unchecked") public class Solution { - private int m; - private int forcedMask; - private int[] adj; - private char[] idxToChar = new char[26]; - private int[] charToIdx = new int[26]; - private boolean[] used = new boolean[26]; + private int min = Integer.MAX_VALUE; + private List lists = new ArrayList<>(); public List> supersequences(String[] words) { - Arrays.fill(charToIdx, -1); - for (String w : words) { - used[w.charAt(0) - 'a'] = true; - used[w.charAt(1) - 'a'] = true; + boolean[][] pairs = new boolean[26][26]; + int[] counts = new int[26]; + for (String word : words) { + int a = word.charAt(0) - 'a'; + int b = word.charAt(1) - 'a'; + if (!pairs[a][b]) { + pairs[a][b] = true; + counts[a]++; + counts[b]++; + } + } + List[] links = new ArrayList[26]; + for (int i = 0; i < 26; i++) { + links[i] = new ArrayList<>(); } - // Map each used letter to an index [0..m-1] - for (int c = 0; c < 26; c++) { - if (used[c]) { - idxToChar[m] = (char) (c + 'a'); - charToIdx[c] = m++; + int[] counts1 = new int[26]; + int[] sides = new int[26]; + for (int i = 0; i < 26; i++) { + for (int j = 0; j < 26; j++) { + if (pairs[i][j]) { + links[i].add(j); + counts1[j]++; + sides[i] |= 1; + sides[j] |= 2; + } } } - adj = new int[m]; - // Build graph and record forced duplicates - for (String w : words) { - int u = charToIdx[w.charAt(0) - 'a']; - int v = charToIdx[w.charAt(1) - 'a']; - if (u == v) { - forcedMask |= (1 << u); + int[] arr = new int[26]; + for (int i = 0; i < 26; i++) { + 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] |= (1 << v); + arr[i] = -1; } } - // Try all supersets of forcedMask; keep those that kill all cycles - int best = 9999; - List goodSets = new ArrayList<>(); - for (int s = 0; s < (1 << m); s++) { - if ((s & forcedMask) != forcedMask) { - continue; - } - int size = Integer.bitCount(s); - if (size <= best && !hasCycle(s)) { - if (size < best) { - best = size; - goodSets.clear(); - } - goodSets.add(s); + dfs(links, 0, arr, new int[26], 0); + List> res = new ArrayList<>(); + for (int[] arr1 : lists) { + List list = new ArrayList<>(); + for (int n : arr1) { + list.add(n); } + res.add(list); + } + return res; + } + + private void dfs(List[] links, int i, int[] arr1, int[] arr, int n) { + if (n > min) { + return; } - // Build distinct freq arrays from these sets - Set seen = new HashSet<>(); - List> ans = new ArrayList<>(); - for (int s : goodSets) { - int[] freq = new int[26]; - for (int i = 0; i < m; i++) { - freq[idxToChar[i] - 'a'] = ((s & (1 << i)) != 0) ? 2 : 1; + if (i == 26) { + if (!chk(links, arr)) { + return; } - String key = Arrays.toString(freq); - if (seen.add(key)) { - List tmp = new ArrayList<>(); - for (int f : freq) { - tmp.add(f); - } - ans.add(tmp); + if (n < min) { + min = n; + lists = new 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 boolean hasCycle(int mask) { - int[] color = new int[m]; - for (int i = 0; i < m; i++) { - if (((mask >> i) & 1) == 0 && color[i] == 0 && dfs(i, color, mask)) { - return true; + private boolean chk(List[] links, int[] arr) { + for (int i = 0; i < 26; i++) { + if (arr[i] == 1 && dfs1(links, arr, new boolean[26], i)) { + return false; } } - return false; + return true; } - private boolean dfs(int u, int[] color, int mask) { - color[u] = 1; - int nxt = adj[u]; - while (nxt != 0) { - int v = Integer.numberOfTrailingZeros(nxt); - nxt &= (nxt - 1); - if (((mask >> v) & 1) == 1) { - continue; - } - if (color[v] == 1) { - return true; - } - if (color[v] == 0 && dfs(v, color, mask)) { + private boolean dfs1(List[] links, int[] arr, boolean[] seens, int i) { + seens[i] = true; + for (int next : 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/java/g3401_3500/s3435_frequencies_of_shortest_supersequences/SolutionTest.java b/src/test/java/g3401_3500/s3435_frequencies_of_shortest_supersequences/SolutionTest.java index d1b4f8780..3f34bc9c1 100644 --- a/src/test/java/g3401_3500/s3435_frequencies_of_shortest_supersequences/SolutionTest.java +++ b/src/test/java/g3401_3500/s3435_frequencies_of_shortest_supersequences/SolutionTest.java @@ -14,10 +14,10 @@ void supersequences() { equalTo( List.of( List.of( - 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), List.of( - 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)))); }