懸線法 有套路的DP

2022-09-04 07:51:10 字數 2510 閱讀 6714

例題 p1169 [zjoi2007]棋盤製作

西洋棋是世界上最古老的博弈遊戲之一,和中國的圍棋、象棋以及日本的將棋同享盛名。據說西洋棋起源於易經的思想,棋盤是乙個8×88 \times 88×8大小的黑白相間的方陣,對應八八六十四卦,黑白對應陰陽。

而我們的主人公小q,正是西洋棋的狂熱愛好者。作為乙個頂尖高手,他已不滿足於普通的棋盤與規則,於是他跟他的好朋友小w決定將棋盤擴大以適應他們的新規則。

小q找到了一張由n×mn \times mn×m個正方形的格仔組成的矩形紙片,每個格仔被塗有黑白兩種顏色之一。小q想在這種紙中裁減一部分作為新棋盤,當然,他希望這個棋盤盡可能的大。

不過小q還沒有決定是找乙個正方形的棋盤還是乙個矩形的棋盤(當然,不管哪種,棋盤必須都黑白相間,即相鄰的格仔不同色),所以他希望可以找到最大的正方形棋盤面積和最大的矩形棋盤面積,從而決定哪個更好一些。

於是小q找到了即將參加全國資訊學競賽的你,你能幫助他麼?

輸入格式:

包含兩個整數nnn和mmm,分別表示矩形紙片的長和寬。接下來的nnn行包含乙個n ×mn \ \times mn×m的010101矩陣,表示這張矩形紙片的顏色(000表示白色,111表示黑色)。

輸出格式:

包含兩行,每行包含乙個整數。第一行為可以找到的最大正方形棋盤的面積,第二行為可以找到的最大矩形棋盤的面積(注意正方形和矩形是可以相交或者包含的)。

審題可以發現,我們所以尋找的最大矩形其實已經含有正方形,所以不需要單獨去尋找,但是當時我只想到如何dp求正方形,所以分開寫了;

這裡就引進乙個概念——懸線法

求滿足條件的最大矩形或正方形

通過不斷更新矩形左右端點所能到達的距離(1

: 初始化;2:dp中更新)

left [ i ] [ j ] 陣列更新包含第(i,j)點的最左能到達距離;

right [ i ] [ j ] 陣列更新包含第(i,j)點的最右能到達距離;

up [ i ] [ j ] 陣列更新包含第(i,j)點的向上能到達的距離;

ps:為什麼沒有下?因為down可以在dp中用up代替;

1:初始化 left 和 right 陣列

for(int i=1;i<=n;i++)

//右端點從右往左更新

for(int j=2;j<=m;j++)

//左端點從左往右更新

}

2:dp更新 up 陣列和 left,right 陣列

for(int i=1;i<=n;i++)

int a=right[i][j]-left[i][j]+1

;

int b=min(a,up[i][j]);

ans1=max(ans1,b*b);//

正方形做法2

ans2=max(ans2,a*up[i][j]);

}}

思考:該方法的正確性,因為每個點都取到了一次,每次選取最優解,則正解定會取到

完整code(附有正方形另類做法)

#include#define maxn 2007

using

namespace

std;

intn,m,maps[maxn][maxn],ans1;

intf1[maxn][maxn],ans2,up[maxn][maxn];

intleft[maxn][maxn],right[maxn][maxn];

int min(int a,int b)

int max(int a,int b)

void

cube()

else

ans1=max(f1[i][j],ans1);}}

ans1*=ans1;

}int

main()

}cube();

//正方形的做法1

for(int i=1;i<=n;i++)

//右端點從右往左更新

for(int j=2;j<=m;j++)

//左端點從左往右更新

}

for(int i=1;i<=n;i++)

int a=right[i][j]-left[i][j]+1

;

int b=min(a,up[i][j]);

ans1=max(ans1,b*b);//

正方形做法2

ans2=max(ans2,a*up[i][j]);}}

printf(

"%d\n%d\n

",ans1,ans2);

return0;

}

總結與反思;正確靈活使用,可以快速解決問題;

懸線法DP總結

求滿足某種條件 如01交替 的最大矩形 正方形 先預處理出 ml i j mr i j mt i j 分別表示當前位置 i,j 能向左擴充套件到的最左邊的編號 能向右擴充套件到的最右邊的編號 能向上擴充套件到的最大高度。然後在做 dp 時,除第一行,每行根據上一行的狀態更新當前狀態,逐行掃一遍。複雜...

DP小技巧 懸線法

本來以為之前寫過這個方法,今天又考了一道模板題,於是就記錄一下 懸線法是求解一類極大子矩陣問題的dp解法 maybe 考試有人想出了 o n 2log 2n 的二分套二分做法,在此表示膜拜 即二分面積,列舉面積的約數 從暴力方面想,對於乙個點,直接求出它向左右上的最遠距離再乘起來可能不對,所以只能求...

關於懸線法

懸線法的模板題,下面主要講懸線法 懸線法思路 懸線的定義,就是一條豎線,這條豎線要滿足上端點在整個矩形上邊界或者是乙個障礙點。然後以這條懸線進行左右移動,直到移至障礙點或者是矩陣邊界,進而確定這條懸線所在的極大矩陣。具體方法 先預處理 用陣列l,r記錄某點向左和向右能到達的最遠點的縱座標。用陣列up...