#二分,哈希 or dp#洛谷 4398 [JSOI2008]Blue Mary的战役地图

题目

求两个正方形矩阵的最大公共正方形矩阵边长


分析

第一种就是\(dp\)
\(dp[x1][y1][x2][y2]\)表示第一个正方形矩阵以\((x1,y1)\)为右下角,
第二个正方形矩阵以\((x2,y2)\)为右下角所能得到的最大公共正方形矩阵边长
状态转移方程比较显然
第二种是二分:
二分答案,然后预处理和哈希,时间复杂度\(O(n^2log_2n)\)


代码(dp)

#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=51;
int n,a[N][N],b[N][N],ans,dp[N][N][N][N];
inline signed iut(){
	rr int ans=0; rr char c=getchar();
    while (!isdigit(c)) c=getchar();
    while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    return ans;
}
inline signed min(int a,int b){return a<b?a:b;}
inline signed max(int a,int b){return a>b?a:b;}
signed main(){
	n=iut();
	for (rr int i=1;i<=n;++i)
	for (rr int j=1;j<=n;++j) a[i][j]=iut();
	for (rr int i=1;i<=n;++i)
	for (rr int j=1;j<=n;++j) b[i][j]=iut();
	for (rr int ia=1;ia<=n;++ia)
	for (rr int ja=1;ja<=n;++ja)
	for (rr int ib=1;ib<=n;++ib)
	for (rr int jb=1;jb<=n;++jb)
	if (a[ia][ja]==b[ib][jb]){
		rr int t=min(dp[ia][ja-1][ib][jb-1],dp[ia-1][ja][ib-1][jb]);
		dp[ia][ja][ib][jb]=min(dp[ia-1][ja-1][ib-1][jb-1],t)+1;
		ans=max(ans,dp[ia][ja][ib][jb]);
	}
	return !printf("%d",ans);
}

代码(二分)

#include <cstdio>
#include <cctype>
#include <unordered_map>
#define rr register
using namespace std;
typedef unsigned uit;
const uit N=51,bas0=4177,bas1=3977;
unordered_map<uit,bool>uk; int n,a[2][N][N];
uit p1[N],p2[N],h[2][N][N],s[N][N];
inline signed iut(){
	rr int ans=0; rr char c=getchar();
    while (!isdigit(c)) c=getchar();
    while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    return ans;
}
inline void doit(int t,int m){
	for (rr int i=1;i<=n;++i)
	for (rr int j=1;j<=n;++j)
	    s[i][j]=s[i][j-1]*bas0+a[t][i][j];
	for (rr int i=1;i<=n;++i)
	for (rr int j=1;j<=n-m+1;++j)
	    h[t][i][j]=s[i][j+m-1]-s[i][j-1]*p1[m];
	for (rr int j=1;j<=n-m+1;++j)
	for (rr int i=1;i<=n;++i)
	    s[i][j]=s[i-1][j]*bas1+h[t][i][j];
	for (rr int j=1;j<=n-m+1;++j)
	for (rr int i=1;i<=n-m+1;++i)
	    h[t][i][j]=s[i+m-1][j]-s[i-1][j]*p2[m];
}
inline bool check(int m){
	doit(0,m),doit(1,m),uk.clear();
	for (rr int i=1;i<=n-m+1;++i)
	for (rr int j=1;j<=n-m+1;++j) uk[h[0][i][j]]=1;
	for (rr int i=1;i<=n-m+1;++i)
	for (rr int j=1;j<=n-m+1;++j)
	if (uk[h[1][i][j]]) return 1;
	return 0;
}
signed main(){
	n=iut(),p1[0]=p2[0]=1;
	for (rr int i=1;i<=n;++i) p1[i]=p1[i-1]*bas0;
	for (rr int i=1;i<=n;++i) p2[i]=p2[i-1]*bas1;
	for (rr int i=1;i<=n;++i)
	for (rr int j=1;j<=n;++j) a[0][i][j]=iut();
	for (rr int i=1;i<=n;++i)
	for (rr int j=1;j<=n;++j) a[1][i][j]=iut();
	rr int l=1,r=n;
	while (l<r){
		rr int mid=(l+r+1)>>1;
		if (check(mid)) l=mid;
		    else r=mid-1;
	}
	return !printf("%d",l);
}
posted @ 2020-08-04 23:21  lemondinosaur  阅读(98)  评论(0编辑  收藏  举报