您的位置:首页 > 其它

【ZJOI2007】【悬线法】棋盘制作

2013-02-15 01:05 204 查看
最近学习悬线法,所以就找了这道题练练手。

因为棋盘是01交错的,所以我们可以先处理一下棋盘,从而转化为求最大子矩形问题。

第一问可以用DP也可以用悬线法,我DP写得比较熟所以用了DP。

第二问直接用悬线法求出处理过的棋盘的最大子矩形即可

代码:

#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 2000 + 10;
int n,m;
int chess[maxn][maxn],f[maxn][maxn];
int up[maxn][maxn],left[maxn][maxn],right[maxn][maxn];
void init()
{
freopen("chess.in","r",stdin);
freopen("chess.out","w",stdout);
}

void readdata()
{
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i++)
{
for(int j = 1;j <= m;j++)
{
scanf("%d",&chess[i][j]);
if((i + j) & 1)chess[i][j] ^= 1;
}
}
}

int min(int a,int b)
{
return a < b ? a : b;
}

int max(int a,int b)
{
return a > b ? a : b;
}

int dp(int p)
{
int ret = 0;
memset(f,0,sizeof(f));
for(int i = 1;i <= n;i++)
{
for(int j = 1;j <= m;j++)
{
if(chess[i][j] == p)
{
f[i][j] = 1;
f[i][j] = min(f[i-1][j-1],min(f[i-1][j],f[i][j-1])) + 1;
ret = max(ret,f[i][j]);
}
}
}
return ret * ret;
}

int calc(int p)
{
memset(left,0,sizeof(left));
memset(up,0,sizeof(up));
memset(right,0,sizeof(right));
int ret = 0;
for(int i = 1;i <= n;i++)
{
int lo = 0,ro = m + 1;
for(int j = 1;j <= m;j++)
{
if(chess[i][j] == p)
{
up[i][j] = left[i][j] = 0;
lo = j;
}
else
{
up[i][j] = i == 1 ? 1 : up[i-1][j] + 1;
left[i][j] = i == 1 ? lo + 1 : max(left[i-1][j],lo + 1);
}
}
for(int j = m;j >= 1;j--)
{
if(chess[i][j] == p)
{
right[i][j] = m + 1;
ro = j;
}
else
{
right[i][j] = i == 1 ? ro - 1 : min(right[i-1][j],ro - 1);
ret = max(ret,up[i][j] * (right[i][j] - left[i][j] + 1));
}
}
}
return ret;
}

void solve()
{
int ans1 = max(dp(0),dp(1));
int ans2 = max(calc(0),calc(1));
printf("%d\n%d",ans1,ans2);
}

int main()
{
init();
readdata();
solve();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: