Skip to content

Improved tasks 1659, 3435 #1956

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 81 additions & 59 deletions src/main/java/g1601_1700/s1659_maximize_grid_happiness/Solution.java
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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<int[]> lists = new ArrayList<>();

public List<List<Integer>> 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<Integer>[] 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<Integer> 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<List<Integer>> res = new ArrayList<>();
for (int[] arr1 : lists) {
List<Integer> list = new ArrayList<>();
for (int n : arr1) {
list.add(n);
}
res.add(list);
}
return res;
}

private void dfs(List<Integer>[] links, int i, int[] arr1, int[] arr, int n) {
if (n > min) {
return;
}
// Build distinct freq arrays from these sets
Set<String> seen = new HashSet<>();
List<List<Integer>> 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<Integer> 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<Integer>[] 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<Integer>[] 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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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))));
}

Expand Down