洛谷 P1169 ZJOI2007 棋盤製作

2022-05-05 08:09:09 字數 1749 閱讀 1146

給定乙個n*m的01矩陣,尋找最大的,相鄰值不相同的子矩陣與子方陣。

\(n,m\leq 2,000\)

樸素的做法是列舉兩個點來確定矩陣,再暴力判斷能不能滿足條件。

複雜度\(o(n^4)\)**。考慮優化:判斷能不能滿足條件時,存在很多重複判斷,可以預處理。

但是,怎樣進行預處理呢?這就需要我們改變列舉方式,簡化預處理的步驟。

今年應該不考

是一種dp(?)演算法,常用於求滿足條件的矩陣。

如果將一條線當做1*k的矩陣看待,則我們列舉每一條滿足條件的線,並嘗試將其向左右拓展構造矩陣。

那麼只要在左右拓展長度中分別取min,就是所求答案。這種方法的複雜度是多少?

每個點如果和上方不同,就可以接到上面的線中。所以列舉每個點,就可以遞推求出懸線up

\[up_=up_+(b_\not= b_)

\]其中b是原始矩陣,初始值是1。複雜度\(o(n^2)\)

左右端拓展的物件是單個點,所以對於每個點都預處理出能向左右拓展到的位置。用遞推求出。

\[\beginb_\not=b_\quad left_=j\\b_=b_\quad left_=left_\end

\]\[\beginb_\not=b_\quad right_=j\\b_=b_\quad right_=right_\end

\]複雜度仍然\(o(n^2)\)

2k可過。

我們需要證明的是,懸線法可以列舉到所有矩形。

假設我們要在這一團滿足條件的聯通塊中找矩形。(醜,真tm醜)

那麼它會不會取藍色呢?不會,很明顯綠色比他更優。有乙個性質:矩形邊緣必然緊貼聯通塊邊緣

所以對於每條懸線,它取到的矩陣是盡量大的。

(其實綠色也不滿足,因為左右端沒有取完整。)

畫圖寶才,luogu撿到鬼了

由剛才的性質得出,這個矩形所在的聯通塊即便邊緣再粗糙,總是會有一條懸線的上端和矩形的上端重合。

所以,只要每條懸線都列舉到,每個可能是答案的矩形就會列舉到,而且會讓它們盡量大。這題就解決了。

別看了 抄的

#include//iostream庫有left函式,會衝突

#includeusing namespace std;

const int maxn=2005;

int n,m;

bool b[maxn][maxn];

int left[maxn][maxn],right[maxn][maxn],up[maxn][maxn];

int sq,rect,temp;

int main()

temp=(right[i][j]-left[i][j]+1);

rect=max(rect,up[i][j]*temp);

sq=max(sq,min(up[i][j],temp)*min(up[i][j],temp));

//正方形同理。

} printf("%d\n%d\n",sq,rect);

return 0;

}

最後,祝大家身體健康,再見。

洛谷 P1169 ZJOI2007 棋盤製作

西洋棋是世界上最古老的博弈遊戲之一,和中國的圍棋 象棋以及日本的將棋同享盛名。據說西洋棋起源於易經的思想,棋盤是乙個8 times 88 8大小的黑白相間的方陣,對應八八六十四卦,黑白對應陰陽。而我們的主人公小q,正是西洋棋的狂熱愛好者。作為乙個頂尖高手,他已不滿足於普通的棋盤與規則,於是他跟他的好...

P1169 ZJOI2007 棋盤製作

隨手一寫就衝進了最優解的第一頁?本來以為是dp,但是經過仔細分析.這不就是二進位制 單調棧麼?然後想正方形的情況.emm.好像正方形一定是最大矩形的子矩陣吧 聽說此題dp也可行?include include include include include using namespace std t...

P1169 ZJOI2007 棋盤製作 貪心

乙個矩陣中求乙個最大的子矩陣和子正方形使得它們其中都是01交錯。l ef ti,j left lefti,j 表示 i,j i,j i,j 往左擴充套件多遠,rig hti,jright righti j 表示 i,j i,j i,j 往右擴充套件多遠,upi j up up i,j 表示 i,j ...