Description
Blue Mary最近迷上了玩Starcraft(星际争霸) 的RPG游戏。她正在设法寻找更多的战役地图以进一步提高自己的水平。 由于Blue Mary的技术已经达到了一定的高度,因此,对于用同一种打法能够通过的战役地图,她只需要玩一张,她就能了解这一类战役的打法,然后她就没有兴趣再玩儿这一类地图了。而网上流传的地图有很多都是属于同一种打法,因此Blue Mary需要你写一个程序,来帮助她判断哪些地图是属于同一类的。 具体来说,Blue Mary已经将战役地图编码为n*n的矩阵,矩阵的每个格子里面是一个32位(有符号)正整数。对于两个矩阵,他们的相似程度定义为他们的最大公共正方形矩阵的边长。两个矩阵的相似程度越大,这两张战役地图就越有可能是属于同一类的。
Input
第一行包含一个正整数n。 以下n行,每行包含n个正整数,表示第一张战役地图的代表矩阵。 再以下n行,每行包含n个正整数,表示第二张战役地图的代表矩阵。
Output
仅包含一行。这一行仅有一个正整数,表示这两个矩阵的相似程度。
Sample Input
3
1 2 3
4 5 6
7 8 9
5 6 7
8 9 1
2 3 4
1 2 3
4 5 6
7 8 9
5 6 7
8 9 1
2 3 4
Sample Output
2
HINT
样例解释:
子矩阵:
5 6
8 9
为两个地图的最大公共矩阵
约定:
n<=50;
题解:显然可以二分边长。
至于判断是否可行用hash即可。
每次暴力枚举矩阵的右下角用hash值检验是否存在即可。
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<map>
#define P1 23333333
#define P2 10000007
#define N 101
using namespace std;
int n,m,x,num,ans;
unsigned int a[N][N],b[N][N],t1[N],t2[N];
map<unsigned int,int>use;
bool check(int x){
num++;
for(int i=x;i<=n;i++)
for(int j=x;j<=n;j++){
unsigned int temp=a[i][j]-a[i-x][j]*t1[x]-a[i][j-x]*t2[x]+a[i-x][j-x]*t1[x]*t2[x];
use[temp]=num;
}
for(int i=x;i<=n;i++)
for(int j=x;j<=n;j++){
unsigned int temp=b[i][j]-b[i-x][j]*t1[x]-b[i][j-x]*t2[x]+b[i-x][j-x]*t1[x]*t2[x];
if(use[temp]==num) return true;
}
return false;
}
int work(){
int l=1,r=n;
while (l<=r){
int mid=(l+r)>>1;
if (check(mid)) l=mid+1,ans=mid;
else r=mid-1;
}
return ans;
}
int main(){
scanf("%d",&n);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
scanf("%d",&a[i][j]);
for(int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
a[i][j]+=a[i-1][j]*P1;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
a[i][j]+=a[i][j-1]*P2;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
scanf("%d",&b[i][j]);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
b[i][j]+=b[i-1][j]*P1;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
b[i][j]+=b[i][j-1]*P2;
t1[0]=1;t2[0]=1;
for (int i=1;i<=n;i++){t1[i]=t1[i-1]*P1;t2[i]=t2[i-1]*P2;}
printf("%d",work());
}