KMP求最小覆盖子矩阵
来源:互联网 发布:五金进销存软件 编辑:程序博客网 时间:2024/06/08 01:05
Milking Grid
题意:在字符矩阵中找出一个最小子矩阵,使其多次复制所得的矩阵包含原矩阵。
数据范围:1 <= R <= 10,000, 1 <= C <= 75
思路1:
先用KMP的next函数求出每行的最小循环子串的长度L,那么L,2L,3L,...都可以作为该行的循环子串。
此外,还可以存在像AAAABAAA的情况。
设m为mL<=col的最大值,那么由于列最多75,直接通过暴力比较,判断1...mL+1~col是否可以作为循环子串。
至于如何获取所求最小矩阵的宽度,这里采用http://poj.org/showmessage?message_id=153316的方法,
用一个数组统计长度出现的次数,最后从小到大遍历一遍,若出现次数为row的长度,即为我们所求的宽度。
至于高度的话,用KMP的next,每次比较整行,即可求得最小矩阵的高度。
#include <iostream>#include <stdio.h>#include <string.h>#include <algorithm>using namespace std;const int maxr=10002;const int maxc=80;char grid[maxr][maxc]; //大矩阵int row,col;//行和列int rnext[maxr][maxc]; //rnext[i]:对应第i行字符串的next函数int cnext[maxr]; //求纵向的next,每次比较的是整行int rlen[maxr]; //rlen[i]:第i行字符串的最小循环子串的长度int cnt[maxc];//cnt[i]:统计各宽度出现的次数int ans_c,ans_r; //最小覆盖矩阵的宽度和高度void rgetNext(int r,char*str){ int k=0; rnext[r][1]=0; for(int i=1;i<col;i++){ while(k&&str[k]!=str[i]) k=rnext[r][k]; if(str[k]==str[i]) k++; rnext[r][i+1]=k; } rlen[r]=col-rnext[r][col]; int i; for(i=rlen[r];i<=col;i+=rlen[r]){ cnt[i]++; } i-=rlen[r]; //直接通过比较来判断,是否还有可能存在的串,如aaabcaaa,除了5,还可能为6,7,8 //即判断第i+1个字符后的后缀是否和前缀相同 for(int j=i+1;j<=col;j++){ int x=0,y=j;//分别从索引0和y处开始比较 while(str[x]==str[y]){ x++;y++; } if(y==col) cnt[j]++; }}void cgetNext(){ int k=0; cnext[1]=0; for(int i=1;i<row;i++){ while(k&& strcmp(grid[k],grid[i])!=0) k=cnext[k]; if(strcmp(grid[k],grid[i])==0) k++; cnext[i+1]=k; } ans_r=row-cnext[row];}int main(){ scanf("%d%d",&row,&col); for(int i=0;i<row;i++) scanf("%s",grid[i]); memset(cnt,0,sizeof(cnt)); for(int i=0;i<row;i++) rgetNext(i,grid[i]); cgetNext(); for(int i=1;i<=col;i++){ if(cnt[i]==row){ ans_c=i; break; } } printf("%d\n",ans_c*ans_r); return 0;}
思路2:
找出每行的重复子串长度的各种可能情况,然后每行都有的并且是最小长度作为宽width。
第二步找最小重复子矩阵的高,取每行的宽为width的前缀作为一个单位,对这0到r-1个单位求出KMP的next函数,
找出最小重复子序列的单位数作为高height,最终答案为width*height。
#include<stdio.h>#include<string.h>char s[10010][80];int next[10010];int main(){ int i,j,x,y,r,c,f[80]; char a[80]; scanf("%d%d",&r,&c); for(i=0; i<c; i++)f[i]=0; for(i=0; i<r; i++) { scanf("%s",s[i]); strcpy(a,s[i]); //将每行的每种重复子串长度都求出来 for(j=c-1; j>0; j--) { a[j]=0; for(x=0,y=0; s[i][y]; x++,y++) { if(!a[x])x=0; if(a[x]!=s[i][y])break; } if(!s[i][y])f[j]++; } } for(i=0; i<c; i++) //找出所有行的最小相同的子串长度,为最小重复子矩阵的列数 if(f[i]==r)break; x=i;//最小重复子矩阵的列数 for(i=0; i<r; i++)s[i][x]=0; next[0]=-1;//按纵列求KMP的next函数,以求最小重复子矩阵的行数 for(i=1,j=-1; i<r; i++) { while(j!=-1&&strcmp(s[j+1],s[i]))j=next[j]; if(!strcmp(s[j+1],s[i]))j++; next[i]=j; } printf("%d\n",(r-1-next[r-1])*x);//行列相乘即为最终结果 return 0;}
阅读全文
0 0
- KMP求最小覆盖子矩阵
- POJ 2185 Milking Grid(最小覆盖子矩阵面积KMP)
- POJ2185 Milking Grid 最小覆盖子矩阵(二维KMP)
- POJ2185_Milking Grid_KMP_二维求最小覆盖子矩阵
- 最小覆盖子串 KMP
- POJ2185 最小覆盖矩阵 (二维KMP)
- KMP与最小覆盖子串
- KMP与最小覆盖子串
- KMP与最小覆盖子串
- poj2185 KMP+欧几里得 求最小的覆盖
- POJ2185(最小覆盖子矩阵) #by nobody
- poj 2185 Milking Grid(最小矩阵覆盖,二维 kmp 匹配)
- poj2185 Milking Grid(二维KMP+最小覆盖矩阵)
- poj2185(二维最小覆盖子串问题-KMP)
- KMP(最长重复子串 & 最小覆盖)
- HDU 3746 Cyclic Nacklace(KMP最小覆盖子串)
- POJ2185 最小覆盖矩阵
- KMP-最小矩阵
- Folding UVA
- 实现一个函数,打印乘法口诀表,口诀表的行数和列数自己指定, 输入9,输出9*9口诀表,输出12,输出12*12的乘法口诀表。
- 240 Search a 2D Matrix II
- 错误解决方案__20161031重仿.png
- Learning Python Part II 之 作用域(scope)
- KMP求最小覆盖子矩阵
- ubuntu中默认Python2和Python3的转换命令
- CodeForces 867B Save the problem!
- JZOJ 5404. 【NOIP2017提高A组模拟10.10】Graph
- Python 用栈模拟递归
- js原型链
- Leetcode 算法习题 第六周
- Appium Appium 文档翻译计划 2017 完成!
- 实现一个函数判断year是不是闰年。