【棋盤製作】題解

【題目描述】

        國際象棋是世界上最古老的博弈遊戲之一,和中國的圍棋、象棋以及日本的將棋同享盛名。據說國際象棋起源於易經的思想,棋盤是一個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

轉載請註明出處

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