前缀和之最大加权矩形

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;
 }

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值