题目大意:
给出一个n*n的字符矩阵,要求在矩阵当中选出一个m*m(m <= n)的矩阵,使得该m*m的矩阵关于副对角线对称,问m的最大值。
问题分析:
我们用dp[i][j]表示如果ch[i][j]是所选矩阵的左下角的一个元素时,所选矩阵的最大阶数。
我们考虑如下的情况:
1 | 2 | 3 | 4 | |
1 | z | a | b | a |
2 | c | b | a | b |
3 | a | b | b | c |
4 | c | a | c | q |
假设现在我们需要考察dp[i][j],那么我们需要考察第i行第j列的元素相等的数目,假设是m并且我们已经知道dp[i - 1][j + 1],也就是我们知道(i,j)点作为矩阵的左下角的点时向右上扩展,能够选取的最大的矩阵阶数。
1.m>dp[i - 1][j + 1];这时候显然第i行第j列可以作为矩阵((i - 1,j + 1)作为左下角能够扩展出的最大的对称矩阵)的;两条新边,所以dp[i][j] = dp[i - 1][j + 1] + 1;
2.m <= dp[i - 1][j + 1];这个时候显然第i行第j列是无法作为矩阵的新加边的,但是dp[i - 1][j + 1]表示的又是对阵矩阵的阶数,并且他们是同一个副对角线,因而dp[i][j] = m;
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1000 + 5;
char puzzle[maxn][maxn];
int n;
int dp[maxn][maxn];
int main()
{
ios::sync_with_stdio(false);
while(cin >> n)
{
if(n == 0)
break;
string s;
memset(dp, 0, sizeof(dp));
for(int i = 1; i <= n; i++)
{
cin >> s;
stringstream ss(s);
for(int j = 1; j <= n; j++)
ss >> puzzle[i][j];
}
int ans = 1;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
{
int x = i, y = j;
while(x >= 1 && y <= n && puzzle[x][j] == puzzle[i][y])
x--, y++;
int cnt = i - x;
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]);
}
}
cout << ans << endl;
}
return 0;
}