前言
文章仅分享一下个人的思路和可以在我们学校网站全通过的代码,如果有更好的思路欢迎评论分享。本人目前还是个菜鸟,代码写的并不优美,有需要注意的地方还请提出来呀! q(≧▽≦q)
一、问题描述
棋盘是指一个行和列编号从1~N的NxN的二进制矩阵,当行号和列号之和为偶数时该矩阵对应位置为黑色的(1),否则为白色的(0)。以下图示为N=1、2、3时的棋盘。
给出一个NxN的二进制矩阵,请找出位于该矩阵内的最大尺寸的完整棋盘,以及最大尺寸棋盘的数量(棋盘可以交叠)。
【输入形式】
每个测试用例的第一行是一个正整数N(1<=N<=2000),表示給定矩阵的行数和列数,接下来的N行描述了这个矩阵:每行有N个字符,既可以是“1”(代表黑块),也可以是“0”(代表白块)。矩阵至少包含一个“1”字符。
【输出形式】
输出最大尺寸棋盘的行列的大小,以及最大棋盘的个数,以空格分隔。
【样例输入】
5
00101
11010
00101
01010
11101
【样例输出】
3 3
二、思路分析
1.输入
处理输入的时候需要注意的是:输入N之后,输入的并非一个N行N列的二维数组这样的形式,而是N行长度为N的字符串,如果需要的话可以先进行转化
2.如何确定棋盘?
观察棋盘的特点可以发现:棋盘的右下角都是黑格子 既然这样,当一个格子是黑格子的话,那么它就一定能够生成一个棋盘;其次,我们可以认为一个黑格子可以生成多大的棋盘由其左上角的黑格子(如果是黑格子的话)和前方和上方的白格子(如果是白格子的话)决定
我们可以用一个结构体将上述的量全部表示出来:
struct node
{
int bw=0; //黑还是白
int Max=1; //黑块的最大棋盘
int imax=2; //白块的最大横向支持
int jmax=2; //白块的最大纵向支持
};
基本思路是这样的:
如果某个格子是黑格子,对于第一行/列的黑格子,其生成的最大棋盘规模为1;否则呢,判断其左上角是否为一个黑格子,如果该条件也满足,判断其前方和上方的格子是否为白格子,如果也满足,取 x为前方白格子和上方白格子最大横向支持和最大纵向支持中的小者,如果 x大于等于该黑格子左上方黑格子的最大棋盘规模加 1,则该黑格子可以生成的最大棋盘规模就为其左上方黑格子生成的最大棋盘规模加 1,否则就为 x(因为前方和上方的白格子不能支持生成那么大的棋盘嘛),对于不能满足上述某一条件的黑格子,最大就只能生成规模为 1的棋盘了
如果某个格子是白格子,对于第一行/列的白格子,其最大横向、纵向支持都为 2;对于第二行/列,如果它上一个和前一个都为黑格子,则其横向、纵向支持为 3(对于第二行,其实它的横向支持意义不大,理论上横向最大只能支持规模为 2的棋盘,第二列同理,但为了归并情况将它们这样定义);对于其余的白格子,如果其前一个为黑格子且黑格子前一个为白格子,则其最大横向支持为那个白格子的最大横向支持 +2,如果其前一个为黑格子但黑格子前的不是白格子,则其最大横向支持为3,如果其前面的不是黑格子,则其最大横向支持为2,求某一白格子的最大纵向支持同理
3.举个例子
刚才那段文字可能已经看晕了 (∪.∪ )…zzz
下面举个例子解释一下
白格子用一个数对表示 (最大横向支持,最大纵向支持)
黑格子用一个数表示生成的最大棋盘规模
三、代码
//207.棋盘
/*
对于每个白块:
记录该块最大的横向支持和纵向支持
对于第一行:所有的白块横向和纵向支持为 2;
对于第二行:所有的白块如果前一个和上一个为黑块则其横向和纵向支持为 3;否则为 2
对于其余行:如果白块的前一个为黑块
如果黑块的前一个为白块,则横向支持为该白块的横向支持 +2
否则
该白块的横向支持为 3
纵向支持同理
对于每个黑块:
记录该块产生的最大棋盘数
对于第一行/列:所有黑块的最大棋盘数为 1;
对于其余行:如果该块的左上方为黑块(最大棋盘数为x) 则其有可能产生最大为 x+1的棋盘
如果其前方和上方都为白块
取前方白块的最大横向支持和上方白块的最大纵向支持中的小者
如果这个值大于等于 x+1
这个黑块的最大棋盘为 x+1阶的
否则
这个黑块的最大棋盘为 该值
否则
该黑块的最大棋盘为 1阶
*/
#include <iostream>
#include <string>
using namespace std;
struct node
{
int bw=0; //黑还是白
int Max=1; //黑块的最大棋盘
int imax=2; //白块的最大横向支持
int jmax=2; //白块的最大纵向支持
};
int main()
{
int n;
cin>>n;
string *str=new string[n];
node board[100][100];//以上初始化一个二维棋盘
for(int i=0;i<n;i++)
{
cin>>str[i];
}
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(str[i][j]=='0') //以下处理白块
{
board[i][j].bw=0;
if(i==0||(i==1&&j==0))
{
board[i][j].imax=2;
board[i][j].jmax=2;
}
if(i==1)
{
if(board[i][j-1].bw==1&&board[i-1][j].bw==1)
{
board[i][j].imax=3;
board[i][j].jmax=3;
}
else
{
board[i][j].imax=2;
board[i][j].jmax=2;
}
}
if(i>1)
{
if(j==0)
{
board[i][j].imax=2;
if(board[i-1][j].bw==1)
board[i][j].jmax=board[i-2][j].jmax+2;
else
board[i][j].jmax=2;
}
if(j==1)
{
if(board[i][j-1].bw==1)
board[i][j].imax=3;
else
board[i][j].imax=2;
if(board[i-1][j].bw==1)
{
if(board[i-2][j].bw==0)
board[i][j].jmax=board[i-2][j].jmax+2;
else
board[i][j].jmax=3;
}
else
board[i][j].jmax=2;
}
if(j>1)
{
if(board[i][j-1].bw==1)
{
if(board[i][j-2].bw==0)
board[i][j].imax=board[i][j-2].imax+2;
else
board[i][j].imax=3;
}
else
board[i][j].imax=2;
if(board[i-1][j].bw==1)
{
if(board[i-2][j].bw==0)
board[i][j].jmax=board[i-2][j].jmax+2;
else
board[i][j].jmax=3;
}
else
board[i][j].jmax=2;
}
}
}
if(str[i][j]=='1')//以下处理黑块
{
board[i][j].bw=1;
if(i==0||j==0)
{
board[i][j].Max=1;
}
else
{
if(board[i-1][j-1].bw==1)
{
if(board[i-1][j].bw==0&&board[i][j-1].bw==0)
{
int x;
board[i][j-1].imax>board[i-1][j].jmax?x=board[i-1][j].jmax:x=board[i][j-1].imax;
if(x>=board[i-1][j-1].Max+1)
board[i][j].Max=board[i-1][j-1].Max+1;
else
board[i][j].Max=x;
}
else
board[i][j].Max=1;
}
else
board[i][j].Max=1;
}
}
}
}
/*for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(board[i][j].bw==1)
cout<<board[i][j].Max<<" ";
else
cout<<0<<" ";
}
cout<<endl;
}*/
int Max=1,time=0;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(board[i][j].bw==1&&board[i][j].Max==Max)
{
time++;
}
if(board[i][j].bw==1&&board[i][j].Max>Max)
{
Max=board[i][j].Max;
time=1;
}
}
}
cout<<Max<<" "<<time;
delete []str;
return 0;
}
其实并不用写这么长,应该有不必要的部分,有些注释掉的是调了一下(至今不会调试,只能输出调试);如果发现代码与思路不符,可以理解为:思路是从写代码中产生的,代码只是一个草稿纸,写完之后就…懒得改了
总结
该题目主要用到了结构体,将每个格子的信息用结构体表示出来,通过观察(我是画了很多图 ㄟ( ▔, ▔ )ㄏ) 之后,找到格子与格子之间的联系进行求解,虽然需要很多判断,但只那个矩阵进行了一次遍历,时间复杂度为O(n^2)