【棋盘制作】题解

【题目描述】

        国际象棋是世界上最古老的博弈游戏之一,和中国的围棋、象棋以及日本的将棋同享盛名。据说国际象棋起源于易经的思想,棋盘是一个8*8大小的黑白相间的方阵,对应八八六十四卦,黑白对应阴阳。
        而我们的主人公小Q,正是国际象棋的狂热爱好者。作为一个顶尖高手,他已不满足于普通的棋盘与规则,于是他跟他的好朋友小W决定将棋盘扩大以适应他们的新规则。
        小Q找到了一张由N*M个正方形的格子组成的矩形纸片,每个格子被涂有黑白两种颜色之一。小Q想在这种纸中裁减一部分作为新棋盘,当然,他希望这个棋盘尽可能的大。
        不过小Q还没有决定是找一个正方形的棋盘还是一个矩形的棋盘(当然,不管哪种,棋盘必须都黑白相间,即相邻的格子不同色),所以他希望可以找到最大的正方形棋盘面积和最大的矩形棋盘面积,从而决定哪个更好一些。
于是小Q找到了即将参加全国信息学竞赛的你,你能帮助他么?

【数据范围】

对于20%的数据,N, M ≤ 80
对于40%的数据,N, M ≤ 400 
对于100%的数据,N, M ≤ 2000

【题解】

        这道题是浙江省07年的省选题,前几天做过一道类似的题目,所以顺手就刷了一下。这里介绍国家集训队03年的《浅谈用极大化思想解决最大子矩形问题》中提到的一种方法。

        我们先考虑最大的矩形面积。很容易得到,最大的矩形一定是一个极大矩形(即四边都不能向上拓展的矩阵),也就是说,他的上边要么是整个矩阵的上边,要么被一对相同的数卡住。利用这个性质,我们可以得到一个优秀的算法:设行指针i,列指针j,j从左往右,i从上往下扫描,计算出当前点(j,i)与其上方能拓展的最远点所夹的最大矩形面积。由于刚才提到的性质,这样的扫描一定能扫过最大矩形的上下边界,而左右边界则可以用一个O(n^2)的动规来解决。这样,我们就可以在O(n^2)的时间内求出最大矩形。

        而解决了求最大矩形的问题后,最大正方形的问题也就好解决了。套用最大矩形的算法,可以轻松的求出最大正方形,具体实现请参看我的程序。


Code

program chess;
type
        int=longint;
var
        i,j,m,n:int;
        matrix,max_l,max_r:array[0..2001,0..2001]of int;

function min(x,y:int):int;
begin
        if x<y then exit(x)
                else exit(y);
end;

procedure prepare;
begin
        for i:=1 to n do
                for j:=2 to m do
                        if(matrix[i,j]<>matrix[i,j-1])then
                                max_l[i,j]:=max_l[i,j-1]+1
                        else max_l[i,j]:=0;
        for i:=1 to n do
                for j:=m-1 downto 1 do
                        if(matrix[i,j]<>matrix[i,j+1])then
                                max_r[i,j]:=max_r[i,j+1]+1
                        else max_r[i,j]:=0;
        for i:=1 to m do matrix[0,i]:=matrix[1,i];
end;

procedure get_ans;
var min_l,min_r,s,l,ans2,ans:int;
begin
        ans:=0;ans2:=0;
        for j:=1 to m do begin
                for i:=1 to n do begin
                        if matrix[i,j]=matrix[i-1,j]then begin
                                min_l:=maxlongint;min_r:=maxlongint;l:=0;
                        end;
                        min_l:=min(min_l,max_l[i,j]);
                        min_r:=min(min_r,max_r[i,j]);
                        s:=min_l+min_r+1;inc(l);
                        if ans<l*s then ans:=l*s;
                        if ans2<min(l,s)then ans2:=min(l,s);
                end;
        end;
        writeln(ans2*ans2);
        write(ans);
end;

begin
        assign(input,'data.txt');reset(input);
        read(n,m);
        for i:=1 to n do
                for j:=1 to m do read(matrix[i,j]);
        prepare;
        get_ans;
end.



BY QW

转载请注明出处

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章