您的位置:首页 > 其它

HDU 1506 1505 2870 2830

2017-07-09 00:00 260 查看
摘要: 动态规划 矩形面积最大值

1506 连续矩形最大面积

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

#define LL long long
int const MAX = 1e6 + 1;
int const INF = 1 << 30;

using namespace std;

//分别记录第i个柱子的高度和左右能够延伸的最远的柱子

LL H[MAX], L[MAX], R[MAX];
int main(int argc, char*argv[]) {
int n;

while ( scanf("%d", &n) == 1 && n ) {
for ( int i = 1; i <= n; i++ ) {
scanf("%lld", H + i);
L[i] = i;
R[i] = i;
}

//由第2个开始更新左边,L[i]表示第i个矩形可以延伸到的最左边的柱子
//L[i]-1 就是最左边柱子的左边
for ( int i = 2; i <= n; i++ ) {
while ( H[L[i] - 1] >= H[i] ) {
L[i] = L[L[i] - 1];
if ( L[i] == 1 )
break;
}

}

//更新右边由n-1个开始,R[i]表示第i个矩形可以延伸的最右边的柱子
for ( int i = n - 1; i >= 1; i-- )
while ( H[R[i] + 1] >= H[i] ) {
R[i] = R[R[i] + 1];
if ( R[i] == n )
break;
}

LL ans = -1;
for ( int i = 1; i <= n; i++ ) {
LL t = ( R[i] - L[i] + 1 ) * H[i];
if ( t > ans )
ans = t;
}
printf("%lld\n", ans);

}

return 0;
}


1505

题目大意:给出一个n * m 的矩形,求全为F的矩形面积最大。
题目思路:这道题和HDU1506很像。
d[i][j]表示第i行j列元素在前i行中的最大高度。(以第一行为底)例如测试样例:



然后和HDU-1506思路一样,
找出以当前点位最低点能左右延伸的最长距离,也就是找出最左最右的下标,最后的 ans = max(num[i]*(r[i]-l[i]+1))

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

#define LL long long
int const MAX = 1111;
int const INF = 1 << 30;

using namespace std;

int mp[MAX][MAX], L[MAX], R[MAX], H[MAX][MAX];
int n, m;

int main(int argc, char*argv[]) {
int T;

scanf("%d", &T);
while ( T-- ) {

scanf("%d%d", &n, &m);

char s[3];
for ( int i = 1; i <= n; i++ )
for ( int j = 1; j <= m; j++ ) {
scanf("%s", s);
//F代表可用,设为1,方便计算高度
if ( s[0] == 'F' ) mp[i][j] = 1;
else mp[i][j] = 0;
}

//计算每行点的高度和左右最长可延伸的位置,类似1506
for ( int i = 1; i <= n; i++ ) {
//计算第i行第j列的高度
for ( int j = 1; j <= m; j++ ) {
//如果不可用
if ( mp[i][j] == 0 ) H[i][j] = 0;
//可以使用滚动数组
else H[i][j] = H[i - 1][j] + 1;
}
}

/*
for ( int i = 1; i <= n; i++ ) {
for ( int j = 1; j <= m; j++ )
printf("%d  ", H[i][j]);
printf("\n");
}
*/
//对每一行使用1506的做法进行计算
int ans = -1;
for ( int i = 1; i <= n; i++ ) {
//计算左边
for ( int j = 1; j <= m; j++ )
L[j] = R[j] = j;

for ( int j = 2; j <= m; j++ ) {
while ( H[i][L[j] - 1] >= H[i][j] ) {
L[j] = L[L[j] - 1];
if ( L[j] == 1 )
break;
}
}
//计算右边

for ( int j = m - 1; j >= 1; j-- ) {
while ( H[i][R[j] + 1] >= H[i][j] ) {
R[j] = R[R[j] + 1];
if ( R[j] == m )
break;
}

7fe8
}
/*
for ( int j = 1; j <= m; j++ )
printf("%d ", L[j]);
printf("\n");
for ( int j = 1; j <= m; j++ )
printf("%d ", R[j]);
printf("\n");
*/
//计算总的
for ( int j = 1; j <= m; j++ ) {
int t = ( R[j] - L[j] + 1 ) * H[i][j];
if ( t > ans )
ans = t;
}

}

printf("%d\n", ans * 3);

}

return 0;
}


2830

分析:扫描每一行,以该行作为底,用dp存放每一列1达到的高度,然后将高度排序(当然,不能直接对dp排序,因为扫下一行的有用),很容易就能找出最大的面积.最后就可以找出整体的最大值了

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

#define LL long long
int const MAX = 1111;
int const INF = 1 << 30;

using namespace std;
int mp[MAX][MAX], H[MAX][MAX], L[MAX], R[MAX];
int n, m;
void show() {
for ( int i = 1; i <= n; i++ ) {
for ( int j = 1; j <= m; j++ )
printf("%d ", mp[i][j]);
printf("\n");
}
for ( int i = 1; i <= n; i++ ) {
for ( int j = 1; j <= m; j++ )
printf("%d ", H[i][j]);
printf("\n");
}
}

int main(int argc, char*argv[]) {

while ( scanf("%d %d", &n, &m) == 2 ) {
char s[1111];
for ( int i = 1; i <= n; i++ ) {
scanf("%s", s + 1);
for ( int j = 1; j <= m; j++ )
mp[i][j] = s[j] - '0';
}

for ( int i = 1; i <= n; i++ )
for ( int j = 1; j <= m; j++ ) {
if ( mp[i][j] == 1 ) H[i][j] = H[i - 1][j] + 1;
else H[i][j] = 0;
}

// show();
//先按照高度排序,再对每一行使用1505的方法即可
int ans = -1;
for ( int i = 1; i <= n; i++ ) {

for ( int j = 1; j <= m; j++ )
L[j] = R[j] = j;
sort(&H[i][1], &H[i][m] + 1);

//计算左边
for ( int j = 2; j <= m; j++ ) {
while ( H[i][L[j] - 1] >= H[i][j] ) {
L[j] = L[L[j] - 1];
if ( L[j] == 1 )
break;
}

}
//计算右边
for ( int j = m - 1; j >= 1; j-- ) {
while ( H[i][R[j] + 1] >= H[i][j] ) {
R[j] = R[R[j] + 1];
if ( R[j] == m )
break;
}

}

//计算总和
for ( int j = 1; j <= m; j++ ) {
int t = ( R[j] - L[j] + 1 ) * H[i][j];
ans = max(t, ans);
}
}
printf("%d\n", ans);

}

return 0;
}


2870

题意:一个由字符a,b,c,w,x,y,z组成的矩阵,其中w,x,y,z可以转换成a,b,c中的某几个字符,问该矩阵可以组成的由相同字符构成的最大子矩阵。

分析:DP。首先想到要求的子矩阵一定是由相同字符构成的,所以可以枚举w,x,y,z分别转换成a,b,c后得到的最大子矩阵即可。

枚举最大矩形是由哪个字母构成的

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

#define LL long long
int const MAX = 1111;
int const INF = 1 << 30;

using namespace std;
int n, m;
char mp[MAX][MAX];
int H[MAX][MAX], L[MAX], R[MAX];
int ans = -1;

//根据不同的字母计算出的H,计算最大值
void dp() {
for ( int i = 1; i <= n; i++ ) {
//计算左边
for ( int j = 1; j <= m; j++ )
L[j] = R[j] = j;

for ( int j = 2; j <= m; j++ ) {
while ( H[i][L[j] - 1] >= H[i][j] ) {
L[j] = L[L[j] - 1];
if ( L[j] == 1 )
break;
}
}
//计算右边

for ( int j = m - 1; j >= 1; j-- ) {
while ( H[i][R[j] + 1] >= H[i][j] ) {
R[j] = R[R[j] + 1];
if ( R[j] == m )
break;
}

}
/*
for ( int j = 1; j <= m; j++ )
printf("%d ", L[j]);
printf("\n");
for ( int j = 1; j <= m; j++ )
printf("%d ", R[j]);
printf("\n");
*/
//计算总的
for ( int j = 1; j <= m; j++ ) {
int t = ( R[j] - L[j] + 1 ) * H[i][j];
ans = max(ans, t);
}

}
}
int main(int argc, char*argv[]) {
while ( scanf("%d %d", &n, &m) == 2 ) {
ans = -1;
for ( int i = 1; i <= n; i++ )
scanf("%s", mp[i] + 1);

//由a构成
for ( int i = 1; i <= n; i++ ) {
for ( int j = 1; j <= m; j++ ) {
if ( mp[i][j] == 'a' || mp[i][j] == 'w' || mp[i][j] == 'y' || mp[i][j] == 'z' ) {
H[i][j] = H[i - 1][j] + 1;
} else {
H[i][j] = 0;
}
}
}
dp();
for ( int i = 1; i <= n; i++ ) {
for ( int j = 1; j <= m; j++ ) {
if ( mp[i][j] == 'c' || mp[i][j] == 'x' || mp[i][j] == 'y' || mp[i][j] == 'z' ) {
H[i][j] = H[i - 1][j] + 1;
} else {
H[i][j] = 0;
}
}
}
dp();
for ( int i = 1; i <= n; i++ ) {
for ( int j = 1; j <= m; j++ ) {
if ( mp[i][j] == 'b' || mp[i][j] == 'w' || mp[i][j] == 'x' || mp[i][j] == 'z' ) {
H[i][j] = H[i - 1][j] + 1;
} else {
H[i][j] = 0;
}
}
}
dp();
printf("%d\n", ans);
}

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