题意:一个最大500*500的字符矩阵,求最大的两个相同的字符正方形。正方形可以有重叠部分但不能重合。
解法:首先是二分正方形的长度,然后判断某个长度存在时候计算字符矩阵的二维hash值,二维hash的方法是:
这样子拓展的hash算法可以O(1) 获取任意一个子矩阵的hash值。
代码:
/****************************************************** * @author:xiefubao *******************************************************/ #pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <queue> #include <vector> #include <algorithm> #include <cmath> #include <map> #include <set> #include <stack> #include <string.h> //freopen ("in.txt" , "r" , stdin); using namespace std; #define eps 1e-8 #define zero(_) (abs(_)<=eps) const double pi=acos(-1.0); typedef unsigned long long LL; const int Max=502; const LL INF=100007; char s[Max][Max]; LL hash[Max][Max]; LL hash2[Max][Max]; LL scale[Max]; LL scale2[Max]; LL seed=3131; LL seed2=1313; int n,m; int count1=0; struct edge { LL data; int next; int x,y; } edges[Max*Max]; int head[100010]; int tot=0; void add(LL u,LL data,int x,int y) { edges[tot].data=data; edges[tot].x=x; edges[tot].y=y; edges[tot].next=head[u]; head[u]=tot++; } int have(LL value) { LL t=value%INF; for(int i=head[t];i!=-1;i=edges[i].next) { if(edges[i].data==value) return i+1; } return 0; } bool OK(int t) { memset(head,-1,sizeof head); tot=0; for(int i=1; i+t-1<=n; i++) for(int j=1; j+t-1<=m; j++) { LL value=0; value=hash2[i+t-1][j+t-1]-hash2[i+t-1][j-1]*scale[t]-hash2[i-1][j+t-1]*scale2[t]+hash2[i-1][j-1]*scale[t]*scale2[t]; if(have(value)) return true; add(value%INF,value,i,j); } return false; } void solve(int t) { memset(head,-1,sizeof head); tot=0; for(int i=1; i+t<=n+1; i++) for(int j=1; j+t<=m+1; j++) { LL value=0; value=hash2[i+t-1][j+t-1]-hash2[i+t-1][j-1]*scale[t]-hash2[i-1][j+t-1]*scale2[t]+hash2[i-1][j-1]*scale[t]*scale2[t]; int ok=have(value); if(ok) { cout<<edges[ok-1].x<<" "<<edges[ok-1].y<<endl; cout<<i<<" "<<j<<endl; return ; } else add(value%INF,value,i,j); } } int main() { while(cin>>n>>m) { scale[0]=1; scale2[0]=1; for(int i=1; i<Max; i++) scale[i]=scale[i-1]*seed,scale2[i]=scale2[i-1]*seed2; for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) cin>>s[i][j]; for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) { hash[i][j]=hash[i][j-1]*seed+s[i][j]; hash2[i][j]=hash2[i-1][j]*seed2+hash[i][j]; } int left=1; int right= n==m?n-1:min(n,m); while(left<=right) { int middle=(left+right)/2; if(OK(middle)) left=middle+1; else right=middle-1; } if(right==0) cout<<right<<endl; else { cout<<right<<endl; solve(right); } } return 0; }
时间: 2024-10-06 03:36:45