題目背景
感謝@throusea 貢獻的兩組數據
題目描述
回到家中的貓貓把三桶魚全部轉移到了她那長方形大池子中,然後開始思考:到底要以何種方法喫魚呢(貓貓就是這麼可愛,喫魚也要想好喫法 ^_*)。她發現,把大池子視爲01矩陣(0表示對應位置無魚,1表示對應位置有魚)有助於決定喫魚策略。
在代表池子的01矩陣中,有很多的正方形子矩陣,如果某個正方形子矩陣的某條對角線上都有魚,且此正方形子矩陣的其他地方無魚,貓貓就可以從這個正方形子矩陣“對角線的一端”下口,只一吸,就能把對角線上的那一隊鮮魚吸入口中。
貓貓是個貪婪的傢伙,所以她想一口喫掉儘量多的魚。請你幫貓貓計算一下,她一口下去,最多可以喫掉多少條魚?
輸入格式
有多組輸入數據,每組數據:
第一行有兩個整數n和m(n,m≥1),描述池塘規模。接下來的n行,每行有m個數字(非“0”即“1”)。每兩個數字之間用空格隔開。
對於30%的數據,有n,m≤100
對於60%的數據,有n,m≤1000
對於100%的數據,有n,m≤2500
輸出格式
只有一個整數——貓貓一口下去可以喫掉的魚的數量,佔一行,行末有回車。
輸入輸出樣例
輸入 #1複製
4 6 0 1 0 1 0 0 0 0 1 0 1 0 1 1 0 0 0 1 0 1 1 0 1 0
輸出 #1複製
3
說明/提示
右上角的
1 0 0
0 1 0
0 0 1
思路
拿到這題立馬想到了最大正方形那題,可是卻不會推方程。寫了個記憶化搜索。
怎麼去搜?對於任意一個子正方形,要滿足魚都在對角線,也就是對角線的數字不爲0;子正方形其他地方沒有魚,也就是對角線以外都是0。假如(x,y)有魚,那就可以dfs(x+1,y+1)和dfs(x+1,y-1)來判斷對角線上是否有魚。既然一個子正方形只有對角線有魚,那麼該正方形的數字和就是對角線的長度。所以利用二維前綴和把整個矩形總和算出來。
#include <stdio.h>
#include <iostream>
#define N 2501
using namespace std;
int a[N][N],dp[N][N][2],sum[N][N],n,m,s,orgx,orgy;
int tox[5]={0,1,0,-1,0},toy[5]={0,0,1,0,-1};
int dfs1(int x,int y)
{
if(x>n || y>m ) return 0;
//if(dp[x][y][0]) return dp[x][y][0];//爲什麼註釋?下面有解釋
register int cnt(sum[x][y]-sum[orgx-1][y]-sum[x][orgy-1]+sum[orgx-1][orgy-1]);
if(cnt!=x-orgx+1 || a[x][y]==0)
{
return 0;
}
dp[x][y][0]=dfs1(x+1,y+1)+1;
if(dp[x][y][0]) return dp[x][y][0];//爲什麼到這裏才進行記憶化?下面有解釋
}
int dfs2(int x,int y)
{
if(x>n || y<1 ) return 0;
register int cnt(sum[x][orgy]-sum[orgx-1][orgy]-sum[x][y-1]+sum[orgx-1][y-1]);
if(cnt!=x-orgx+1 || a[x][y]==0)
{
return 0;
}
dp[x][y][1]=dfs2(x+1,y-1)+1;
if(dp[x][y][1]) return dp[x][y][1];
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
register int i,j,k;
cin>>n>>m;
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
cin>>a[i][j];
sum[i][j]=sum[i][j]+sum[i][j-1]+sum[i-1][j]-sum[i-1][j-1]+a[i][j];
}
}
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
orgx=i;
orgy=j;
dp[i][j][0]=dfs1(i,j);
}
}
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
orgx=i;
orgy=j;
dp[i][j][1]=dfs2(i,j);
}
}
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
s=max(s,max(dp[i][j][0],dp[i][j][1]));
}
}
cout<<s<<endl;
return 0;
}
接下來來解答代碼註釋中的問題。
假設有如下4*4的矩形:
1 0 1 0
0 1 0 0
1 0 1 0
0 0 0 1
答案是3,但如果把註釋那句話放到前面,答案會就變成2。因爲dp[2][2][0]會先複製成2,再次枚舉到該點時會直接返回,而得不到右下角的正確矩形。