当前位置:首页 > C++目录 > 正文内容

二维数组的差分

亿万年的星光3个月前 (09-13)C++目录18679

一、基本概念

二维数组差分是一种高效处理区间修改操作的数据结构技巧,常用于解决矩阵区域增减问题。

差分是前缀和的逆运算,对于二维数组,差分数组 diff[i][j] 表示原数组 a[i][j]a[i-1][j] + a[i][j-1] - a[i-1][j-1] 的差值。

二维差分是处理子矩阵增减操作的高效方法。

  • 原矩阵a[i][j] (1 ≤ i ≤ m, 1 ≤ j ≤ n)

  • 差分矩阵b[i][j] = a[i][j] - a[i-1][j] - a[i][j-1] + a[i-1][j-1]


二、核心性质

  1. 差分矩阵的前缀和就是原矩阵

  2. 子矩阵增减操作

    • 给以 (x1,y1) 为左上角,(x2,y2) 为右下角的子矩阵每个元素加 c

b[x1][y1] += c
b[x2+1][y1] -= c
b[x1][y2+1] -= c
b[x2+1][y2+1] += c


 因为差分数组的前缀和相当于原数组,所以对差分数组进行以上四个单点操作后,就相当于给原数组数组的区块加上一个值 c


(1)构建方式


	//求出差分数组
for(int i=1; i<=n; i++) {
	for(int j=1; j<=m; j++) {
		b[i][j]=a[i][j]-a[i-1][j]-a[i][j-1]+a[i-1][j-1];
	}
}

(2)增减操作

void add(int x1,int y1,int x2,int y2,int c)   
{
	b[x1][y1] += c;         // 影响从(x1,y1)开始的所有区域
    b[x2 + 1][y1] -= c;     // 消除x方向超出范围的影响
    b[x1][y2 + 1] -= c;         // 消除y方向超出范围的影响
    b[x2 + 1][y2 + 1] += c;   // 补偿多减去的区域(容斥原理)
}


(3)还原操作

b[i][j] += b[i-1][j] + b[i][j-1] - b[i-1][j-1];




四、参考代码

#include <iostream>
using namespace std;

int a[100][100]; // 原始数组 
int b[100][100]; // 差分数组 
int res[100][100]; // 结果数组 

// 区域增加操作
void rangeAdd(int x1, int y1, int x2, int y2, int c) {
    b[x1][y1] += c;
    b[x1][y2+1] -= c;
    b[x2+1][y1] -= c;
    b[x2+1][y2+1] += c;
}

// 从差分数组还原原数组
void restoreArray(int m, int n) {
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            res[i][j] = res[i-1][j] + res[i][j-1] - res[i-1][j-1] + b[i][j];
        }
    }
}

int main() {
    int m, n, c;
    cin >> m >> n;
    
    // 1. 先输入原始数组的值
    cout << "请输入" << m << "行" << n << "列的矩阵:" << endl;
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            cin >> a[i][j];
        }
    }
    
    // 2. 构建差分数组
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            b[i][j] = a[i][j] - a[i-1][j] - a[i][j-1] + a[i-1][j-1];
        }
    }
    
    // 3. 输入修改参数
    cout << "请输入要增加的值c和区域(x1,y1)-(x2,y2):" << endl;
    int a1, b1, a2, b2;
    cin >> c >> a1 >> b1 >> a2 >> b2;
    
    // 4. 执行区域增加操作
    rangeAdd(a1, b1, a2, b2, c);
    
    // 5. 还原数组
    restoreArray(m, n);
    
    // 6. 输出结果
    cout << "修改后的数组:" << endl;
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            cout << res[i][j] << " ";
        }
        cout << endl;
    }
    
    return 0;
}


扫描二维码推送至手机访问。

版权声明:本文由青少年编程知识记录发布,如需转载请注明出处。

分享给朋友:

相关文章

【入门篇】C++ 中变量的简单使用

【入门篇】C++ 中变量的简单使用

1.什么是变量”变量“通俗来讲就是能变的量。在程序设计中,变量是一个个不同类型的盒子,当盒子里装了苹果时,盒子就代表苹果,当然,我们需要给一个个盒子起不同的名字。像下面的图片一样,一个盒子,给他取一个...

【题解】围圈报数(约瑟夫问题)

【题解】围圈报数(约瑟夫问题)

【题目描述】有n个人依次围成一圈,从第1个人开始报数,数到第m个人出列,然后从出列的下一个人开始报数,数到第m个热呢又出列,... ,如此反复到所有的人全部出列为止。设n个人的编号分别为1,2,......

如何使用code::blocks编写C++代码

如何使用code::blocks编写C++代码

在前面的文章中,已经简单介绍了如何下载code::blocks了,这篇文章介绍一下如何使用code::blocks编写一个C++代码我们打开code::blocks软件,点击”New File“然后点...

C++整型的数据范围

数据类型标识符占字节数数值范围数值范围短整型short [int]2(16位)-32768~32767-2^15 到2^15  -1整型[long] int4(32位)-...

【高级篇】C++ 中string的用法

【高级篇】C++ 中string的用法

0.概述string是C++标准库的一个重要部分,本意是字符串,和字符数组不同的是,字符数组是通过一个一个字符模拟的字符串,而string本身就是字符串,string在处理字符串问题时,十分强大。1....

多重背包问题

一、问题定义有 n 种物品,每种物品有三个属性:重量 weight[i](正整数)价值 value[i](正整数)数量 count[i](正整数,表示...