p1169 [zjoi2007]棋盤製作
題意:給出乙個01矩陣,求最大01相間的正方形和長方形面積
用三個陣列left[i][j],right[i][j],up[i][j]分別表示(i,j)這個點符合條件的最左邊界、最右邊界,和最大高度
左右邊界可以預處理:
for 行:
for 右->左:
if 當前位置(i,j)和右邊一格(i,j+1)的值不同(需要01相間):
right[i][j] = right[i][j+1]
相似處理左邊界,這樣每個點都知道了它的左右邊界。
然後從上到下,一行一行列舉每個點,如果當前點和上面的那個點是不同的,就記錄一下公共的左右邊界,更新當前點的高度
up[i][j] = up[i-1][j] + 1
這時可以計算出新增了這行後上面的合法矩形擴張後的面積,更新答案
#includeusing namespace std;
const int n=2005;
int mp[n][n];
int le[n][n],ri[n][n],up[n][n];
int main()
}for(int i=1;i<=n;i++)//處理右邊界
for(int j=m-1;j>=1;j--)
if(mp[i][j]!=mp[i][j+1])
ri[i][j]=ri[i][j+1];
for(int i=1;i<=n;i++)//處理左邊界
for(int j=2;j<=m;j++)
if(mp[i][j]!=mp[i][j-1])
le[i][j]=le[i][j-1];
int ans1=0,ans2=0;
for(int i=1;i1&&mp[i][j]!=mp[i-1][j])//不是第一行,且這個點和上面的點不同
int w=ri[i][j]-le[i][j]+1;//寬
int x=min(w,up[i][j]);//正方形邊長肯定是矩形中短的那條
ans1=max(ans1,x*x);//更新正方形的答案
ans2=max(ans2,w*up[i][j]);//更新長方形的答案}}
printf("%d\n%d\n",ans1,ans2);
return 0;
}
p4147玉蟾宮
題意:給出乙個由『f』和『r』構成的矩陣,求出最大的僅含有『f』的矩陣面積*3
跟上面那題基本相同,判斷條件改下即可
mp[i][j] == 相鄰格仔 && mp[i][j] == 'f'
#includeusing namespace std;
const int n=1005;
char mp[n][n];
int le[n][n],ri[n][n],up[n][n];
char s[2];
int main()
getchar();
}for(int i=1;i<=n;i++)
for(int j=m-1;j>=1;j--)
if(mp[i][j]==mp[i][j+1]&&mp[i][j]=='f')
ri[i][j]=ri[i][j+1];
for(int i=1;i<=n;i++)
for(int j=2;j<=m;j++)
if(mp[i][j]==mp[i][j-1]&&mp[i][j]=='f')
le[i][j]=le[i][j-1];
int ans=0;
for(int i=1;i<=n;i++)
int w=ri[i][j]-le[i][j]+1;
ans=max(ans,w*up[i][j]);}}
printf("%d\n",3*ans);
return 0;
}
p2701[usaco5.3]巨大的牛棚big barn
題意:求最大的僅含有空地的正方形邊長
幾乎是一樣的題目
#includeusing namespace std;
const int n=1005;
int mp[n][n];
int le[n][n],ri[n][n],up[n][n];
int main()
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int i=1;i<=n;i++)
for(int j=n-1;j>=1;j--)
if(mp[i][j]==mp[i][j+1]&&mp[i][j]==0)
ri[i][j]=ri[i][j+1];
for(int i=1;i<=n;i++)
for(int j=2;j<=n;j++)
if(mp[i][j]==mp[i][j-1]&&mp[i][j]==0)
le[i][j]=le[i][j-1];
int ans=0;
for(int i=1;i<=n;i++)
int w=ri[i][j]-le[i][j]+1;
int x=min(w,up[i][j]);
ans=max(ans,x);}}
printf("%d\n",ans);
return 0;
}
p1387最大正方形
題意:求最大僅含有1的正方形
#includeusing namespace std;
const int n=1005;
int mp[n][n];
int le[n][n],ri[n][n],up[n][n];
int main()
for(int i=1;i<=n;i++)
for(int j=m-1;j>=1;j--)
if(mp[i][j]==mp[i][j+1]&&mp[i][j]==1)
ri[i][j]=ri[i][j+1];
for(int i=1;i<=n;i++)
for(int j=2;j<=m;j++)
if(mp[i][j]==mp[i][j-1]&&mp[i][j]==1)
le[i][j]=le[i][j-1];
int ans=0;
for(int i=1;i<=n;i++)
int w=ri[i][j]-le[i][j]+1;
int x=min(w,up[i][j]);
ans=max(ans,x);}}
printf("%d\n",ans);
return 0;
}
關於懸線法
懸線法的模板題,下面主要講懸線法 懸線法思路 懸線的定義,就是一條豎線,這條豎線要滿足上端點在整個矩形上邊界或者是乙個障礙點。然後以這條懸線進行左右移動,直到移至障礙點或者是矩陣邊界,進而確定這條懸線所在的極大矩陣。具體方法 先預處理 用陣列l,r記錄某點向左和向右能到達的最遠點的縱座標。用陣列up...
懸線法 棋盤製作
description 西洋棋是世界上最古老的博弈遊戲之一,和中國的圍棋 象棋以及日本的將棋同享盛名。據說西洋棋起源於易經的思想,棋盤是乙個8 8大小的黑白相間的方陣,對應八八六十四卦,黑白對應陰陽。而我們的主人公小q,正是西洋棋的狂熱愛好者。作為乙個頂尖高手,他已不滿足於普通的棋盤與規則,於是他跟...
懸線法DP總結
求滿足某種條件 如01交替 的最大矩形 正方形 先預處理出 ml i j mr i j mt i j 分別表示當前位置 i,j 能向左擴充套件到的最左邊的編號 能向右擴充套件到的最右邊的編號 能向上擴充套件到的最大高度。然後在做 dp 時,除第一行,每行根據上一行的狀態更新當前狀態,逐行掃一遍。複雜...