激光炸弹(二维前缀和)

激光炸弹(二维前缀和)_第1张图片

import java.io.*;


/*
 * 题目分析:一个最大5000 * 5000 的矩阵, 爆炸范围在 [0,10e9]
 * 地图上的目标是随机分布,如果要暴力计算每一个区间R的权值,会很麻烦
 * 可以用二维前缀和先将权值存起来
 * for(int i = 1;i <= n;i ++) {
			for(int j = 1;j <= m;j ++) {
				g[i][j] = g[i][j-1] + g[i-1][j] - g[i-1][j-1] + read[j-1];
			}
		}
		//前缀和下标有出现-1,所以下标从1开始算。真正的有效下标应该是[1,5001]
		 
	再遍历其中的每个区间R * R取一个最大值
	其中(n,m) 表示距离远点最远的那个点(只遍历有目标的位置)
	for(int i = R;i <= n; i++)
         for(int j = R;j <= m; j++)
            res = Math.max(res,s[i][j] - s[i - R + 1 - 1][j] - s[i][j-R+1-1] + s[i-R+1-1][j-R+1-1]);
    
        所以读入位置的时候,除了要更新该位置的权值w,还要不断更新n,m.用来后序遍历
        当 R < 5001,可以用上面的式子算,如果 R >= 5001,就把R设置成 5001,否则进不去循环    
        如果把R设置成5001,一般n,m也到不了那么大,所以初始化n = m = R (防止出现爆炸范围大于所以目标位置)
    
        半径为R的爆炸范围可以摧毁 (R + 1)(R + 1)个点 但因为爆炸范围要与边平行,所以少炸一个
        因为只有范围 R * R能炸到,所以爆炸点上下、左右的跨度只有 R - 1;
        在算前缀和的时候, x1 = x2 - (R - 1) - 1  == x2 - R        
        
        
 */
public class Main {
	static int n,m;	//其中(n,m) 表示距离远点最远的那个点
	static final int N = 5010;
	static int[][] s = new int[N][N];	//用于存放前缀和
	//输入较多,用BufferedReader
	static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
	
	public static void main(String[] args) throws IOException {
		int cnt,R;	//表示目标个数和爆炸范围
		String[] init = in.readLine().split(" ");
		cnt = Integer.parseInt(init[0]);
		//R最多取到地图边界
		R = Math.min(5001, Integer.parseInt(init[1]));
		
		//因为要从R ~ n,与R ~ m遍历所有目标,所以如果 n < R 或者 m < R 会遍历不到
		//所以先让n = m = R
		n = m = R;
		
		while(cnt -- > 0) {
			//init可以复用
			init = in.readLine().split(" ");
			int x = Integer.parseInt(init[0]);
			int y = Integer.parseInt(init[1]);
			int w = Integer.parseInt(init[2]);
			//计算前缀和下标从1开始,题目是从0开始,所有把题目的所有下标都++
			x++;
			y++;
			n = Math.max(n,x);
			m = Math.max(m,y);
			s[x][y] += w;
		}
		for(int i = 1;i <=n; i ++) {
			for(int j = 1;j <= m; j ++) {
				s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];
			}
		}
		
		//遍历半径为R的正方形
		int res = 0;
		for(int i = R;i <= n;i ++) {
			for(int j = R;j <= m;j ++) {
				res = Math.max(res, s[i][j] - s[i - R][j] - s[i][j - R] + s[i - R][j - R]);
			}
		}
		System.out.println(res);
		in.close();
	}
  
}

前缀和例题:一维版前缀和

                     二维前缀和

你可能感兴趣的:(算法,算法,数据结构,java,蓝桥杯,矩阵)