P1719 最大加权矩形 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
这个题目有两种解法,一种是基于暴力枚举和二位维前缀和得到的答案
二位前缀和的思路,我们使用二维前缀和来预处理,只有开四个for循环来枚举矩形的左起点和右下方的点。来求,时间复杂度达到10的8次方维230
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.math.MathContext;
import java.security.PublicKey;
import java.sql.SQLIntegrityConstraintViolationException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Objects;
import java.util.PriorityQueue;
import java.util.Scanner;
import java.util.TreeMap;
import java.util.TreeSet;
public class Main {
public static void main(String[] args) throws NumberFormatException, IOException {
Scanner sc=new Scanner(System.in);
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
PrintWriter pw1=new PrintWriter(System.out);
//String[] aStrings=br.readLine().split(" ");
aa=sc.nextInt();
bb=new int[aa+1][aa+1];
pre=new int[aa+1][aa+1];
int a;
int b;
for(a=1;a<=aa;a++) {
for(b=1;b<=aa;b++) {
bb[a][b]=sc.nextInt();
}
}
for(a=1;a<=aa;a++) {
for(b=1;b<=aa;b++) {
pre[a][b]=pre[a-1][b]+pre[a][b-1]+bb[a][b]-pre[a-1][b-1];
// System.out.println("A"+pre[a][b]);
}
}
int c;
int d;
int answer=0;
for(a=1;a<=aa;a++) {
for(b=1;b<=aa;b++) {
for(c=a;c<=aa;c++) {
for(d=b;d<=aa;d++) {
answer=Math.max(answer, pre[c][d]-pre[a-1][d]-pre[c][b-1]+pre[a-1][b-1]);
}
}
}
}
System.out.println(answer);
}
public static int aa;
public static int[][] bb;
public static int[][] pre;
}
毫秒
一种是dp加不规则的前缀和的答案
我们首先来看一n*1的矩形来求最大加权矩形,不难发现这就是求最大子段之和。
有状态转移方程d[e]=Math.max(d[e-1]+c, c);
那么扩展到二位矩形怎么半,
我们可以将n*n的矩形进行压缩,怎么压缩?
举个例子
3 3 3 3
3 3 3 3
1 2 3 4
5 6 3 4
这是4*4的矩形,我们从第二行第二列开始取到第四行第四列为止。
是 3 3 3
2 3 4
6 3 4
我们压缩,压缩为一行有11 9 11然后按照一维的矩形来做即可
那么关键有了,怎么预处理压缩,使用到preaa[a][b]=preaa[a-1][b]+preaa[a][b];
然后我们枚举上界和下界。之后枚举第几列,这样将压缩后的值直接按照最长子段来求即可
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.math.MathContext;
import java.security.PublicKey;
import java.sql.SQLIntegrityConstraintViolationException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Objects;
import java.util.PriorityQueue;
import java.util.Scanner;
import java.util.TreeMap;
import java.util.TreeSet;
public class Main {
public static void main(String[] args) throws NumberFormatException, IOException {
Scanner sc=new Scanner(System.in);
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
PrintWriter pw1=new PrintWriter(System.out);
//String[] aStrings=br.readLine().split(" ");
aa=sc.nextInt();
preaa=new int[aa+1][aa+1];
int a;
int b;
for(a=1;a<=aa;a++) {
for(b=1;b<=aa;b++) {
preaa[a][b]=sc.nextInt();
preaa[a][b]=preaa[a-1][b]+preaa[a][b]//按列预处理
}
}
int answer=0;
for(a=1;a<=aa;a++) {//枚举列的上界
for(b=a;b<=aa;b++) {//枚举列的的下界
int c=0;//记录压缩后的序列的每个值
int[] d=new int[aa+1];
for(int e=1;e<=aa;e++) {
c=preaa[b][e]-preaa[a-1][e];
d[e]=Math.max(d[e-1]+c, c);//求出前n个连续数值的的最长数值和
answer=Math.max(answer, d[e]);//取最大值
}
}
}
System.out.println(answer);
}
public static int aa;
public static int[][] preaa;
}