HDU 2870【DP_求最大矩阵】

题目:http://acm.hdu.edu.cn/showproblem.php?pid=2870

题意:给出一个字符矩阵Matritx[][], 求其最大子矩阵, 详细如题.

解题思路:

  将全部字符依次转化a, b, c, 再分别求出这三个矩阵的最大子矩阵即可.

  于是, 问题转化为求矩阵中最大的子矩阵了.

  设置一个变量Num[][]记录位置的最大高度, Num[i][j]表示Matritx[i][j]位置上的最大高度

  这样, 只要枚举以各个Num[i][j]为矩阵最小高度, 分别向前后推进扩展矩阵, 如果Num[i][j + 1] >= Num[i][j]则可以向前扩展, 同理Num[i][j - 1] >= Num[i][j]则可以向后扩展, 用H[j], T[j]分别表示当前位置 j 向前向后扩展的最大位置

  这样, 可以得到一个DP式, 用以优化算法计算过程

    H[j] = H[H[j] - 1], if Num[i][j] <= Num[i][H[j] - 1];

    T[j] = T[T[j] + 1], if Num[i][j] <= Num[i][T[j] + 1];

  那么, 以Num[i][j]为最小高度的最大矩阵为 Num[i][j] * (T[j] - H[j] + 1), 枚举所有的i, j, 取最大解.

1 #include < iostream >
2 #include < cstdio >
3 #include < string >
4 #include < cstring >
5 #include < algorithm >
6 #include < vector >
7 #include < map >
8
9 using namespace std;
10
11 struct TT
12 {
13 int a;
14 int b;
15 int c;
16 }M[ 300 ];
17 const int MAX = 1000 + 10 ;
18 int n, m;
19 int Num[ 3 ][MAX][MAX];
20 int H[MAX], T[MAX];
21
22 void init()
23 {
24 for ( int i = 0 ; i <= n; ++ i)
25 {
26 for ( int j = 1 ; j <= m; ++ j)
27 {
28 Num[ 0 ][i][j] = 0 ;
29 Num[ 1 ][i][j] = 0 ;
30 Num[ 2 ][i][j] = 0 ;
31 }
32 }
33 }
34
35 int solve()
36 {
37 int Ans = 0 ;
38 for ( int i = 0 ; i < 3 ; ++ i)
39 {
40 for ( int j = 1 ; j <= n; ++ j)
41 {
42 Num[i][j][ 0 ] = Num[i][j][m + 1 ] = - 1 ;
43 for ( int k = 1 ; k <= m; ++ k)
44 H[k] = T[k] = k;
45 for ( int k = 2 ; k <= m; ++ k)
46 {
47 while (Num[i][j][k] <= Num[i][j][H[k] - 1 ])
48 H[k] = H[H[k] - 1 ];
49 }
50 for ( int k = m - 1 ; k >= 1 ; -- k)
51 {
52 while (Num[i][j][k] <= Num[i][j][T[k] + 1 ])
53 T[k] = T[T[k] + 1 ];
54 }
55 for ( int k = 1 ; k <= m; ++ k)
56 if (Num[i][j][k] * (T[k] - H[k] + 1 ) > Ans)
57 Ans = Num[i][j][k] * (T[k] - H[k] + 1 );
58 }
59 }
60 return Ans;
61 }
62
63 bool isValid( char c)
64 {
65 if (c == ' a ' || c == ' b ' || c == ' c ' ||
66 c == ' w ' || c == ' x ' || c == ' y ' ||
67 c == ' z ' )
68 return true ;
69 return false ;
70 }
71 int main()
72 {
73 freopen( " in.txt " , " r " ,stdin);
74 char c[MAX];
75 M[ ' a ' ].a = M[ ' a ' ].b = M[ ' a ' ].c = 0 ;
76 M[ ' b ' ].a = M[ ' b ' ].b = M[ ' b ' ].c = 1 ;
77 M[ ' c ' ].a = M[ ' c ' ].b = M[ ' c ' ].c = 2 ;
78 M[ ' w ' ].a = M[ ' w ' ].c = 0 ;
79 M[ ' w ' ].b = 1 ;
80 M[ ' x ' ].a = M[ ' x ' ].c = 1 ;
81 M[ ' x ' ].b = 2 ;
82 M[ ' y ' ].a = M[ ' y ' ].c = 0 ;
83 M[ ' y ' ].b = 2 ;
84 M[ ' z ' ].a = 0 ;
85 M[ ' z ' ].b = 1 ;
86 M[ ' z ' ].c = 2 ;
87
88 while (scanf( " %d%d " , & n, & m) != EOF)
89 {
90 init();
91 for ( int i = 1 ; i <= n; ++ i)
92 {
93 scanf( " %s " , c);
94 for ( int j = 0 ; j < m; ++ j)
95 {
96 if ( ! isValid(c[j]))
97 continue ;
98 Num[M[c[j]].a][i][j + 1 ] = Num[M[c[j]].a][i - 1 ][j + 1 ] + 1 ;
99 Num[M[c[j]].b][i][j + 1 ] = Num[M[c[j]].b][i - 1 ][j + 1 ] + 1 ;
100 Num[M[c[j]].c][i][j + 1 ] = Num[M[c[j]].c][i - 1 ][j + 1 ] + 1 ;
101 }
102 }
103 printf( " %d\n " , solve());
104 }
105 return 0 ;
106 }

转载于:https://www.cnblogs.com/Kenfly/archive/2011/04/18/2020110.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值