ZOJ 3616 Choir III 最大权子矩阵

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3616

题意:

给一个n*m的矩阵,不能选负数,要求一个子矩阵,使得该子矩阵所有值加起来最大。还有一个限制,矩阵元素有1和2两类,要求所选子矩阵两类元素数目各不少于一个值。

分析:

就是最大权子矩阵。以前学的,好久没写这类题,也忘得差不多了,推了一会想起了一个o(n^2m)的做法。先对每列做前缀和的预处理,然后枚举两行,依靠前缀和可以o(1)得到某列这两行之间元素的和,也就是把这两行之间都压缩了,然后就是一维的一个最大子段和问题,可以o(n)地做,即一直累加,小于0就重置为0。不能选负数就把负数设成负无穷,另一个限制只要统计一下就可以,如果满足了再尝试更新答案。

 

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 #include<cstdlib>
 7 #include<set>
 8 #include<map>
 9 #include<queue>
10 #include<ctime>
11 #include<string>
12 using namespace std;
13 
14 typedef long long LL;
15 const LL inf = 847483647ll;
16 
17 struct node{
18     LL v;
19 int t;
20 } a[110][2100];
21 LL sum[2100][110], boy[2100][110], girl[2100][110];
22 
23 int n, m, b, g;
24 int main()
25 {
26     while(scanf("%d %d %d %d", &n, &m, &b, &g) != EOF)
27     {
28         for (int i = 1; i <= n; i++)
29             for (int j = 1; j <= m; j++){
30                 scanf("%lld %d", &a[i][j].v, &a[i][j].t);
31                 if (a[i][j].v < 0) a[i][j].v = -inf;
32             }
33         for (int i = 1; i <= m; i++){
34             sum[i][0] = boy[i][0] = girl[i][0] = 0;
35             for (int j = 1; j <= n; j++){
36                 sum[i][j] = sum[i][j-1] + a[j][i].v;
37                 boy[i][j] = boy[i][j-1];
38                 girl[i][j] = girl[i][j-1];
39                 if (a[j][i].t == 1) boy[i][j]++;
40                 else girl[i][j] ++;
41             }
42         }
43         LL ans = -1;
44         LL cursum, curb, curg;
45         for (int i = 1; i <= n; i++){
46             for (int j = i; j <= n; j++){
47                 cursum = curb = curg = 0;
48                 for (int k = 1; k <= m; k++){
49                     cursum = cursum + sum[k][j] - sum[k][i-1];
50                     curb = curb + boy[k][j] - boy[k][i-1];
51                     curg = curg + girl[k][j] - girl[k][i-1];
52                     if (cursum < 0){
53                         cursum = curb = curg = 0;
54                     }
55                     else{
56                         if (curb >= b && curg >= g) ans = max(ans, cursum);
57                     }
58                 }
59             }
60         }
61         if (ans == -1) puts("No solution!");
62         else printf("%lld\n", ans);
63     }
64     return 0;
65 }

 

posted @ 2014-08-28 15:36  james47  阅读(237)  评论(0编辑  收藏  举报