小美拿到了一个长度为的字符串,她希望将字符串从左到右平铺成一个矩阵(先平铺第一行,然后是第二行,以此类推,矩阵有行列,必须保证,即每个字符换行,共行)。
该矩阵的权值定义为这个矩阵的连通块数量。小美希望最终矩阵的权值尽可能小,你能帮小美求出这个最小权值吗?
注:我们定义,上下左右四个方向相邻的相同字符是连通的。
第一行输入一个正整数,代表字符串的长度。
第二行输入一个长度为的、仅由小写字母组成的字符串。
输出一个整数表示最小权值。
9 aababbabb
2
平铺为3*3的矩阵:
aab
abb
abb
共有2个连通块,4个a和5个b。
import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); char[] str = sc.next().toCharArray(); int q = n; for (int i = 1; i <= n; i++) { if (n % i == 0) { int N = i; int M = n / i; int[][] board = new int[N][M]; int index = 0; for (int j = 0; j < N; j++) { for (int k = 0; k < M; k++) { board[j][k] = str[index++]; } } q = Math.min(q, q(board)); } } System.out.println(q); } public static int q(int[][] board) { int N = board.length; int M = board[0].length; UnionFind uf = new UnionFind(N * M); for (int i = 0; i < N; i++) { for (int j = 0; j < M; j++) { int cur = i * M + j; if (i - 1 >= 0 && board[i - 1][j] == board[i][j]) { uf.union(cur - M, cur); } if (i + 1 < N && board[i + 1][j] == board[i][j]) { uf.union(cur + M, cur); } if (j - 1 >= 0 && board[i][j - 1] == board[i][j]) { uf.union(cur - 1, cur); } if (j + 1 < M && board[i][j + 1] == board[i][j]) { uf.union(cur + 1, cur); } } } return uf.size(); } public static class UnionFind { private int[] parent; private int[] sizeMap; private int size; public UnionFind(int N) { size = N; parent = new int[N]; sizeMap = new int[N]; for (int i = 0; i < N; i++) { parent[i] = i; sizeMap[i] = 1; } } public int size() { return size; } private int find(int v) { if (v != parent[v]) { parent[v] = find(parent[v]); } return parent[v]; } public void union(int v1, int v2) { int f1 = find(v1); int f2 = find(v2); if (f1 != f2) { size--; int s1 = sizeMap[f1]; int s2 = sizeMap[f2]; if (s1 > s2) { parent[f2] = f1; sizeMap[f1] += s2; } else { parent[f1] = f2; sizeMap[f2] += s1; } } } } }