小美拿到了一个长度为
的字符串,她希望将字符串从左到右平铺成一个矩阵(先平铺第一行,然后是第二行,以此类推,矩阵有
行
列,必须保证
,即每
个字符换行,共
行)。
该矩阵的权值定义为这个矩阵的连通块数量。小美希望最终矩阵的权值尽可能小,你能帮小美求出这个最小权值吗?
注:我们定义,上下左右四个方向相邻的相同字符是连通的。
第一行输入一个正整数,代表字符串的长度。
第二行输入一个长度为的、仅由小写字母组成的字符串。
输出一个整数表示最小权值。
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;
}
}
}
}
}