题目大意:给定一个矩阵,要你找到一个最小的矩阵,这个矩阵的无限扩充的矩阵包含着原来的矩阵
思路:乍一看这一题确实很那做,因为我们不知道最小矩阵的位置,但是仔细一想,如果我们能把矩阵都放在左上角该多好,这样一来这一题好像又是循环数组那个样子了(二维的)。
而事实上我们确实可以把所有情况都放在左上角,因为矩阵里面的元素的相对位置是不变的,这样一来我们就可以把矩阵看成都是一些元素从左上角往右下角扩充。那么现在问题就又回到了循环节的问题上了,我们可以把矩阵看成是很多很多个字符串组成,我们要找的就是一个最小的循环节的面积(一维的循环节是可以找长度,二维的循环节我们找面积)。
那怎么找呢?既然是二维的,每一行和每一列都看成是一个新的“元素”(注意这里是以列和行为单位的,而不是以单个元素为单位,如果这题以单个元素为单位会出现严重的错误,这是网上很多AC代码的通病,我们先往下看)。一般的我们可以先这么想,我们可以先固定行,确定最小循环节的列数,然后以这个循环节的列数来找循环节的行数(把每一行都看成是新的元素),比如
abab
baba
cdcd
dcdc
我们可以枚举每一行的循环节的长度(注意这里我用的是枚举),列举所有可能的循环情况,找到公共的最短的循环节的列数,比如例子里面所有行的公共的最短循环列数是2
那么我们就可以在这个矩阵
ab
ba
cd
dc
里面找到循环节的行数,把每一行都看成一个元素,那么这个最长的行数是4,最小循环节的面积是4。
按照这个思路我们可以写出这样的代码
1 #include <iostream> 2 #include <algorithm> 3 #include <functional> 4 #include <string.h> 5 6 using namespace std; 7 8 typedef char * _String; 9 void SearchMatch(const int, _String); 10 void Get_Next(const int, const int); 11 12 static char grid[10010][80], tmp[80]; 13 static int _Next[10010], cir_match[10010]; 14 15 int main(void)//穷举法(500+ms) 16 { 17 int line, colum, min_newmatrix_col, i; 18 while (~scanf("%d%d", &line, &colum)) 19 { 20 memset(cir_match, 0, sizeof(cir_match)); 21 for (i = 0; i < line; i++) 22 { 23 scanf("%s", grid[i]); 24 strcpy(tmp, grid[i]); 25 SearchMatch(colum, grid[i]); 26 } 27 for (i = 0; i < colum; i++) 28 if (cir_match[i] == line) 29 break; 30 31 min_newmatrix_col = i; 32 Get_Next(line, min_newmatrix_col); 33 printf("%d ", min_newmatrix_col*(line - _Next[line])); 34 //colum - _Next[colum]就是关于行的循环节最小长度 35 } 36 return EXIT_SUCCESS; 37 } 38 39 void SearchMatch(const int length, _String match_line) 40 { 41 int pos1, pos2; 42 //cir_match是统计每一行的非循环节的所有值,全部枚举找出最大的即可 43 for (int j = length - 1; j > 0; j--) 44 { 45 //枚举所有循环节长度 46 //理论上j==Length是不用统计的,因为如果不存在比len的最小循环节,那么最小的非循环节只能是长度为len 47 tmp[j] = '