题意不再赘述。
思路:采取一个由里及外的dp思路。
设置状态:dp[i][j],我看大多数题解都说的是最大的对称矩阵,但我觉得还不是特别明确.
dp[i][j],代表以i,j为左下角,向右上角扩散的最大对称矩阵
这样的设置我们就可以得出一个转移方程。因为我们推得i,j位置时,其右上角的矩阵的最大对称矩阵肯定已经推得。所以dp[i][j]可以由dp[i-1][j+1].
这里我们详细来思考下dp[i][j]的对称矩阵大小应该是多少。
便于叙述,下面矩阵默认1为第一行和第一列即左上角为(1,1)。
1 2 3
1 2 2
1 1 1
看这个矩阵。
dp[1][3] = 1,这是很显然的,因为只有它本身一个元素。
然后我们去看dp[2,2].因为dp[1,3]已经是我们推得的。
所以我们去延伸它,
即去比较第2列和第二行以[2,2]开始向上和向右延伸的数是否都相等。
这里我们可以发现[1,2]和[2,3]相等。
所以我们需要去看dp[1,3]是多少。
如果我们延伸的范围刚好或者超过了dp[1,3]的范围。
那么我们也最多是在dp[1,3]的基础上加1.
如果比dp[1,3]小,那么dp[2,2]就是这个延伸的范围了.
别的位置都是同理的递推思路。
AC code
#include<iostream>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<math.h>
#include<stack>
#include<map>
#include<limits.h>
#include<vector>
#include<string.h>
#include<string>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int N = 1e3+5;
const int M = 10007;
#define pi acos(-1)
#define INF 1e8
#define INM INT_MIN
#define pb(a) push_back(a)
#define mk(a,b) make_pair(a,b)
#define dbg(x) cout << "now this num is " << x << endl;
#define met0(axx) memset(axx,0,sizeof(axx));
#define metf(axx) memset(axx,-1,sizeof(axx));
#define sd(ax) scanf("%d",&ax)
#define sld(ax) scanf("%lld",&ax)
#define sdd(ax,bx) scanf("%d %d",&ax,&bx)
#define sddd(ax,bx,cx) scanf("%d %d %d",&ax,&bx,&cx)
#define sfd(ax) scanf("%lf",&ax)
#define sfdd(ax,bx) scanf("%lf %lf",&ax,&bx)
#define pr(a) printf("%d\n",a)
#define plr(a) printf("%lld\n",a)
int n,dp[N][N];
string mp[N];
int main()
{
while(sd(n),n)
{
for(int i=0;i<n;++i) cin >> mp[i];
met0(dp);
int ans = 1;
for(int i=0;i<n;++i)
{
for(int j=0;j<n;++j)
{
int la = i,lb = j,cnt = 0;
dp[i][j] = 1;//本身
if(i == 0 || j == n-1) continue;//无法向右上角扩散
la--,lb++,cnt++;
while(la >= 0 && lb <= n-1 && mp[la][j] == mp[i][lb]) la--,lb++,cnt++;
if(cnt > dp[i-1][j+1]) dp[i][j] = dp[i-1][j+1]+1;
else dp[i][j] = cnt;
ans = max(ans,dp[i][j]);
}
}
pr(ans);
}
system("pause");
return 0;
}