小美拿到了一个长度为
的字符串,她希望将字符串从左到右平铺成一个矩阵(先平铺第一行,然后是第二行,以此类推,矩阵有
行
列,必须保证
,即每
个字符换行,共
行)。
该矩阵的权值定义为这个矩阵的连通块数量。小美希望最终矩阵的权值尽可能小,你能帮小美求出这个最小权值吗?
注:我们定义,上下左右四个方向相邻的相同字符是连通的。
第一行输入一个正整数,代表字符串的长度。
第二行输入一个长度为的、仅由小写字母组成的字符串。
输出一个整数表示最小权值。
9 aababbabb
2
平铺为3*3的矩阵:
aab
abb
abb
共有2个连通块,4个a和5个b。
#include <bits/stdc++.h>
using namespace std;
void backtrace(const string &str, bool *const flags, int x, int y, int row, int col, char c)
{
int idx = row * y + col;
if (row < 0 || row >= x || col < 0 || col >= y || flags[idx] || str[idx] != c)
return;
flags[idx] = true;
backtrace(str, flags, x, y, row + 1, col, c);
backtrace(str, flags, x, y, row - 1, col, c);
backtrace(str, flags, x, y, row, col + 1, c);
backtrace(str, flags, x, y, row, col - 1, c);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n;
cin >> n;
string str;
cin >> str;
bool flags[n];
long long ret = LONG_LONG_MAX;
for (int x = 1; x < n; ++x)
{
if (n % x)
continue;
int y = n / x;
fill(flags, flags + n, false);
long long cnt = 0;
for (int row = 0; row < x; ++row)
{
for (int col = 0; col < y; ++col)
{
int idx = row * y + col;
if(!flags[idx])
{
++cnt;
backtrace(str, flags, x, y, row, col, str[idx]);
}
}
}
ret = min(ret, cnt);
}
cout << ret;
} import java.util.Scanner;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
// 注意 hasNext 和 hasNextLine 的区别
while (in.hasNextInt()) { // 注意 while 处理多个 case
int n = in.nextInt();
in.nextLine();
char[] cs = in.nextLine().toCharArray();
int res = n;
for(int i=1;i<n;i++){
if(n%i==0){
int row = i;
int col = n/i;
char[][] board = new char[row][col];
int[][] used = new int[row][col];
for(int j=0,count=0;j<row;j++){
for(int k=0;k<col;k++){
board[j][k] = cs[count++];
}
}
int num = 0;
for(int j=0;j<row;j++){
for(int k=0;k<col;k++){
if(used[j][k]==0){
dfs(board,used,j,k,++num);
}
}
}
res = Math.min(res,num);
}
}
System.out.println(res);
}
}
public static void dfs(char[][] board,int[][] used,int i,int j,int count){
if(i<0||j<0||i>=board.length||j>=board[0].length||used[i][j]!=0){
return;
}
used[i][j]=count;
if(i>0&&board[i-1][j]==board[i][j]){
dfs(board, used,i-1,j,count);
}
if(i<board.length-1&&board[i+1][j]==board[i][j]){
dfs(board, used,i+1,j,count);
}
if(j>0&&board[i][j-1]==board[i][j]){
dfs(board, used,i,j-1,count);
}
if(j<board[0].length-1&&board[i][j+1]==board[i][j]){
dfs(board, used,i,j+1,count);
}
}
} dfs
nn = int(input()) s = list(input()) # 行列可能的情况 mn=[] for i in range(1,nn): if nn%i==0: mn.append((i,nn//i)) #回溯 def dfs(row,col,m,n,c): ##用行列来计算在一维数组中的角标 i = row*n+col if row< 0&nbs***bsp;row>=m&nbs***bsp;col<0&nbs***bsp;col>=n&nbs***bsp;used[i]==1&nbs***bsp;s[i]!=c: return used[i] = 1 dfs(row+1,col,m,n,c) dfs(row-1,col,m,n,c) dfs(row,col+1,m,n,c) dfs(row,col-1,m,n,c) #计算 min_res=float('inf') for m,n in mn: used = [0 for _ in range(nn)] res=0 for i in range(m): for j in range(n): idx = i*n+j if used[idx]==0: ##如果某个元素未被检索到,则这次会检索到并且res+=1 res+=1 dfs(i,j,m,n,s[idx]) min_res=min(min_res,res) print(min_res)
#include <iostream>
#include <string>
#include <vector>
using namespace std;
vector<pair<int, int>> getTwoFactorizations(int n) {
vector<pair<int, int>> result;
for (int i = 2; i <= n / 2; i++) { // 只检查前半部分
if (n % i == 0) { // i 是 n 的因子
result.push_back({ i, n / i });
}
}
return result;
}
int main() {
int len;
cin >> len;
string str;
cin >> str;
auto ways = getTwoFactorizations(len);
int ans = 1;
char pre = str[0];
for (int i = 1; i < len; i++) {
if (str[i] != pre) {
ans++;
pre = str[i];
}
}
vector<int>visited(len);
int row_size = 0;
int col_size = 0;
int dirs[4][2] = { {0, 1}, {0, -1}, {-1, 0}, {1, 0} };
auto dfs = [&](auto&& dfs, int row, int col, char cur) ->void {
for (auto dir : dirs) {
int new_row = row + dir[0];
int new_col = col + dir[1];
if (new_row >= 0 && new_row < row_size && new_col >= 0 && new_col < col_size &&
!visited[new_row * col_size + new_col] && str[new_row * col_size + new_col] == cur) {
visited[new_row * col_size + new_col] = 1;
dfs(dfs, new_row, new_col, cur);
}
}
return;
};
for (auto way : ways) {
visited.assign(visited.size(), 0); // 重新填充整个 vector 为 0
row_size = way.first;
col_size = way.second;
int temp = 0;
for (int i = 0; i < row_size; i++) {
for (int j = 0; j < col_size; j++) {
if (!visited[i * col_size + j]) {
temp++;
visited[i * col_size + j] = 1;
dfs(dfs, i, j, str[i * col_size + j]);
}
}
}
ans = min(ans, temp);
}
cout << ans << endl;
} import java.util.Scanner;
public class Main {
//四个方向
private static final int[][] DIRECT = {
{0, 1},
{0, -1},
{1, 0},
{-1, 0}
};
//检查是否越界
private static boolean check(int x, int y, int m, int n) {
return x >= 0 && x < m && y >= 0 && y < n;
}
private static int getMax(char[] chars, int length) {
int ans = Integer.MAX_VALUE;
for (int m = 1; m * m <= length; m++) {
if (length % m == 0) {
int n = length / m;
//m*n的矩阵
ans = Math.min(ans, getCount(chars, m, n, length));
//n*m的矩阵
ans = Math.min(ans, getCount(chars, n, m, length));
}
}
return ans;
}
private static int getCount(char[] chars, int row, int column, int length) {
UnionFind unionFind = new UnionFind(length);
for (int i = 0; i < row; i++) {
for (int j = 0; j < column; j++) {
//沿着四个方向,看能否合并
for (int[] d : DIRECT) {
int nextI = i + d[0], nextJ = j + d[1];
//(i, j)在原来的位置:i * column + j
if (check(nextI, nextJ, row, column) && chars[i * column + j] == chars[nextI * column + nextJ]) {
unionFind.union(i * column + j, nextI * column + nextJ);
}
}
}
}
return unionFind.getCount();
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int length = in.nextInt();
String s = in.next();
System.out.println(getMax(s.toCharArray(), length));
}
}
class UnionFind {
private int[] parent;
private int[] rank;
//连通分量的大小
private int count;
public UnionFind(int n) {
parent = new int[n];
rank = new int[n];
for (int i = 0; i < n; i++) {
parent[i] = i;
}
count = n;
}
public int find(int x) {
while (x != parent[x]) {
parent[x] = parent[parent[x]];
x = parent[x];
}
return x;
}
public void union(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if (rootX == rootY) {
return;
}
if (rank[rootX] > rank[rootY]) {
parent[rootY] = rootX;
count--;
return;
}
if (rank[rootX] < rank[rootY]) {
parent[rootX] = rootY;
count--;
return;
}
parent[rootX] = rootY;
rank[rootY]++;
count--;
}
public int getCount() {
return count;
}
} 简单的因式分解+并集查
package main
import (
"fmt"
"math"
)
// 计算给定矩阵维度下的连通块数量
func calcBlocks(s string, rows, cols int) int {
matrix := make([][]byte, rows)
for i := range matrix {
matrix[i] = make([]byte, cols)
}
// 填充矩阵
for i, c := range s {
matrix[i/cols][i%cols] = byte(c)
}
// 计算连通块
blocks := 0
visited := make([][]bool, rows)
for i := range visited {
visited[i] = make([]bool, cols)
}
for i := 0; i < rows; i++ {
for j := 0; j < cols; j++ {
if !visited[i][j] {
dfs(matrix, visited, i, j, matrix[i][j])
blocks++
}
}
}
return blocks
}
// 深搜
func dfs(matrix [][]byte, visited [][]bool, i, j int, char byte) {
if i < 0 || j < 0 || i >= len(matrix) || j >= len(matrix[0]) || visited[i][j] || matrix[i][j] != char {
return
}
visited[i][j] = true
dfs(matrix, visited, i+1, j, char)
dfs(matrix, visited, i-1, j, char)
dfs(matrix, visited, i, j+1, char)
dfs(matrix, visited, i, j-1, char)
}
func main() {
var n int
var s string
fmt.Scan(&n)
fmt.Scan(&s)
minBlocks := math.MaxInt32
// 尝试所有可能的行数x,因为x*y=n
for x := 1; x <= n; x++ {
if n%x == 0 {
y := n / x
blocks := calcBlocks(s, x, y)
if blocks < minBlocks {
minBlocks = blocks
}
}
}
fmt.Println(minBlocks)
}
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;
}
}
}
}
}
#include <iostream>#include <vector>#include <cstring>using namespace std;class UFD{private:vector<int> father;public:UFD(int n){for(int i = 0; i < n; i++)father.push_back(i);}int find(int num){if(father[num] != num)father[num] = find(father[num]);return father[num];}void connect(int start, int end){start = find(start);end = find(end);if(start != end)father[end] = start;}};int sumConnectedBlock(string& str, int n, int m){UFD ufd = UFD(str.length());for(int i = 0; i < n; i++){for(int j = 0; j < m; j++){if(i > 0 && str[(i - 1)*m + j] == str[i*m + j])ufd.connect((i - 1)*m + j, i*m + j);if(j > 0 && str[i*m + j - 1] == str[i*m + j])ufd.connect(i*m + j - 1, i*m + j);}}int cnt = 0;for(int i = 0; i < str.length(); i++){cnt += ufd.find(i) == i;}return cnt;}int main() {int n;cin >> n;string str;cin >> str;int min_cnt = 10000;for(int i = 1; i <= n; i++){if(n % i == 0){int cnt = sumConnectedBlock(str, i, n / i);min_cnt = min(min_cnt, cnt);}}cout << min_cnt << endl;return 0;}
import java.util.*;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
static int c ;
static ArrayList<Integer[]> set = new ArrayList<>(Arrays.asList(new Integer[] {0, 1},
new
Integer[] {0, -1}, new Integer[] {1, 0}, new Integer[] {-1, 0}));
static int h;
static int l;
static boolean[][] isvisit;
static char[][] graph;
static int fin=Integer.MAX_VALUE;
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
// 注意 hasNext 和 hasNextLine 的区别
while (in.hasNextInt()) { // 注意 while 处理多个 case
int a = in.nextInt();
in.nextLine();
String s = in.nextLine();
int slen = s.length();
for (int i1 = 1; i1 <= (int)(Math.sqrt(slen)); i1++) {
if ((slen / i1)*i1==slen) {
for (int m=0;m<2;m++){
if (m==0){
h = i1;
l = slen / i1;
}
else {
l = i1;
h = slen / i1;
}
graph = new char[h][l];
c=0;
for (int i = 0; i < h; i++) {
for (int j = 0; j < l; j++) {
graph[i][j] = s.charAt(i * l + j);
//System.out.println(s.charAt(i*l+j));
}
}
//System.out.println(h+" t "+l);
isvisit = new boolean[h][l];
for (int i = 0; i < h; i++) {
for (int j = 0; j < l; j++) {
if (!isvisit[i][j]) {
// for (int i1=0;i1<h;i1++){
// for (int j1=0;j1<l;j1++){
// //System.out.println(isvisit[i1][j1]);
// }}
c++;
dfs(i, j);
}
}
}
//System.out.println(h+" "+l+" "+c);
fin =Math.min(fin,c);
}
}
}
System.out.println(fin);
}
}
static void dfs(int a, int b) {
isvisit[a][b] = true;
for (Integer[] tr : set) {
int ta = a + tr[0];
int tb = b + tr[1];
if (ta >= 0 & ta < h && tb >= 0 && tb < l && !isvisit[ta][tb] &&
graph[a][b] == graph[ta][tb]) {
dfs(ta, tb);
}
}
}
} #include <iostream>
#include <bits/stdc++.h>
using namespace std;
int res = INT_MAX;
int cnt;
int rowCnt;
int colCnt;
bool isValid(int i,int j){
return i<rowCnt && j<colCnt && i>=0 && j>=0;
}
void dfs(vector<string>&mat,vector<vector<bool>>& isVisited,int i,int j){
isVisited[i][j]=1;
if(isValid(i+1,j) && mat[i][j]==mat[i+1][j] &&!isVisited[i+1][j]) dfs(mat,isVisited,i+1,j);
if(isValid(i,j+1) && mat[i][j]==mat[i][j+1] &&!isVisited[i][j+1]) dfs(mat,isVisited,i,j+1);
if(isValid(i-1,j) && mat[i][j]==mat[i-1][j] &&!isVisited[i-1][j]) dfs(mat,isVisited,i-1,j);
if(isValid(i,j-1) && mat[i][j]==mat[i][j-1] &&!isVisited[i][j-1]) dfs(mat,isVisited,i,j-1);
}
int getWeight(string& s,int m,int n){
cnt = 0;
vector<vector<bool>> isVisited(m,vector<bool>(n,0));
vector<string> mat(m,"");
colCnt = n;
rowCnt = m;
int k=0;
for(const auto& c:s){
if((int)(mat[k].length())==n) k+=1;
mat[k] += c;
}
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(!isVisited[i][j]){
cnt++;
dfs(mat,isVisited,i,j);
}
}
}
return cnt;
}
int main(){
ios::sync_with_stdio(false);
string s;
int x;
cin>>x>>s;
for(int i=1;i<x;++i){
if(x%i==0){
int m = x/i;
int n = i;
res = min(res,getWeight(s,m,n));
}
}
cout<< res;
return 0;
} #include <climits>
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
struct Pos {
int x;
int y;
Pos(int a, int b) {
x = a;
y = b;
}
};
int lianTong(vector<vector<char>>& v) {
int ret = 0;
vector<vector< int>> dp(v.size(), vector<int>(v[0].size(), 0));
for (int i = 0; i < dp.size(); i++) {
for (int j = 0; j < dp[i].size(); j++) {
if (dp[i][j] == 0) {
queue<Pos> q;
int sum = 1;
char base = v[i][j];
q.push(Pos(i, j));
dp[i][j] = 1;
while (!q.empty()) {
// 向上找
int x = q.front().x;
int y = q.front().y;
if ( x - 1 >= 0 && dp[x - 1][y] == 0 && v[x - 1][y] == base) {
sum++;
q.push(Pos(x - 1, y));
dp[x-1][y] =1;
}
// 向下找
if ( x + 1 < dp.size() && dp[x + 1][y] == 0 && v[x + 1][y] == base) {
sum++;
q.push(Pos(x + 1, y));
dp[x+1][y] =1;
}
// 向左找
if ( y - 1 >= 0 && dp[x][y - 1] == 0 && v[x][y - 1] == base) {
sum++;
q.push(Pos(x, y - 1));
dp[x][y -1] =1;
}
// 向又找
if ( y + 1 < dp[x].size() && dp[x ][y + 1] == 0 && v[x ][y + 1] == base) {
sum++;
q.push(Pos(x, y + 1));
dp[x][y +1] =1;
}
q.pop();
}
if (sum > 0) ret++;
}
}
}
return ret;
}
int main() {
int n;
cin >> n;
string s;
cin >> s;
int min = INT_MAX;
for(int row=1;row<n+1;row++){
int col = n/row;
if(col *row ==n){
vector<vector<char>> v(row,vector<char>(col,'0'));
for(int i=0;i<row;i++){
for(int j=0;j<col;j++){
v[i][j] = s[i*col+j];
}
}
int ret = lianTong(v);
if (min > ret) min = ret;
}
}
cout << min << endl;
}
// 64 位输出请用 printf("%lld") #include <bits/stdc++.h>
using namespace std;
class DSU{
public:
vector<int> nums;
DSU(int n ){
nums.resize(n);
for(int i = 0; i < n; ++i)
nums[i] = i;
}
int findParent(int x){
int y = x;
while(y != nums[y])
y = nums[y];
while(x != nums[x]){
int temp = x;
x = nums[x];
nums[temp] = y;
}
return y;
}
void merge(int x, int y){
int parx = findParent(x);
int pary = findParent(y);
nums[parx] = pary;
}
int getUnion(){
int ans = 0;
for(int i = 0; i < nums.size(); ++i)
if(nums[i] == i)
++ans;
return ans;
}
};
int dfs(const string& str, int m, int n){
DSU dsu(m*n);
for(int i = 0; i < m; ++i)
for(int j = 0; j < n; ++j){
if(i >= 1 && str[(i-1)*n+j] == str[i*n+j])
dsu.merge((i-1)*n+j, i*n+j);
if(j >= 1 && str[i*n+j-1] == str[i*n+j])
dsu.merge(i*n+j-1, i*n+j);
}
return dsu.getUnion();
}
int main(){
int n;
int ans = INT_MAX;
cin >> n;
string str;
cin >> str;
for(int x = 1; x*x <= n; ++x){
if(n%x)
continue;
int y = n/x;
ans = min(ans,dfs(str,x,y));
}
cout << ans << endl;
return 0;
}
// 64 kmnplvqksghziolcfczxpygfiahpgqdaezyjmbwvwgotojprgoqjyeajlqjzrcxd