--差分算法

1.差分

    当我们需要对一个数组中多个不确定区间中所有的值都加上(或者减去)一个常数时,如果一个一个枚举着来加固然简单,但也同时消耗时间,我们可以将每个元素都拆开后再做加减这样就大大减少了程序运行所花费的时间。

2.一维差分

      假如我们现在需要将一个数组a[ N ]中的a[ 1 ]到a[ 10 ]都加上1,我们可以用for循环来挨个做加法,可是如果做加减的数组元素的个数是100呢?甚至10000000....呢?我们程序运行所耗费的时间必定会很长。

     所以我们就构造了数组a[ N ]的一个差分数组b[ N ]。

    而数组中的所有元素a[ i ]都可以看做是数组b[ N ]的前i项和( 和前缀和是刚好相反的 )

    然后,在此基础之上我们就可以进行一种更为简便的运算来达到我们的目的。

(我们以a[ x ]到a[ y ]均加c为例)

首先我们先让b[ x ]加c,然后再让b[ y+1 ]减c。这样我们的目的就达到了。至于为什么,请看下面的讲解。(记住a[ i ]=b[ 1 ]+b[ 2 ]+b[ 3 ]+...+b[ i ]);

那么问题又来了 我们怎么构建这么一个差分数组b[ n ]呢?

很简单

b[0]=a[0];
b[1]=b[0]+a[1];
b[2]=b[1]+a[2];
.....
b[n]=b[n-1]+a[n];

也就是说在输入a[ n ]的时候我们就可以顺便构造了b[ n ];

#include<stdio.h>
#define N 1005
int a[N],b[N];//b[n]是差分数组 
int main()
{
	int n;
	scanf("%d",&n);
	int i=0;
	for(i=1;i<=n;i++){
		scanf("%d",&a[i]);
		b[i]=a[i]-a[i-1];//构造差分数组 
	}
	int l,r,c;
	scanf("%d %d %d",&l,&r,&c);

	b[l]+=c;
	b[r+1]-=c;
	//等价于:
	//for(i=l;i<=r;i++)a[i]+=c; 

	for(i=1;i<=n;i++){
		b[i]=b[i]+b[i-1];
		printf("%d ",b[i]);
	}
	return 0;
}

3.二维差分

其实二维与一维差分联系很大,只需要在一维的基础上稍加修改即可。

我们同样需要构建一个差分数组b[ i ][ j ],而a[ i ][ j ]表示数组b从b[ 1 ][ 1 ]到b[ i ][ j ]这个矩阵中所有元素的和(此时我们可以用到之前二维前缀和的知识)。

 这样我们就构造出来了b[ i ][ j ];

接下来我们来看看如何使用这个二维的差分数组来达到我们的目的

假设我们想要让二维数组a中左上角坐标为(x1,y1)右下角坐标为(x2,y2)的矩阵中所有元素均加c

我们要这样做

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

 接下来请看图解

 最后附上一道例题以及代码

地毯 - 洛谷

//在这道题中数组a和数组b初识值不用输出不用构造,因为全都是0,且c默认为1 
#include<stdio.h>
#include<math.h>
#define N 1009
int map[N][N];
int b[N][N];//差分数组 
int main()
{
	int n,m;
	scanf("%d %d",&n,&m);
	int i=0,j=0;
	int l=0,x1,y1,x2,y2;
	for(l=0;l<m;l++){
		scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
		b[x1][y1]+=1;
		b[x1][y2+1]-=1;
		b[x2+1][y1]-=1;
		b[x2+1][y2+1]+=1;//每次垫一张地毯都会改变数组b的值 
	}
	for(i=1;i<=n;i++){
		for(j=1;j<=n;j++){
			b[i][j]+=(b[i-1][j]+b[i][j-1]-b[i-1][j-1]);
			printf("%d ",b[i][j]);
		}
		printf("\n");
	}
	return 0;
}

这些就是今天的全部内容了

最后希望走在编程这条道路上的小伙伴们可以坚持自己的初心,坚持不懈的走下去,一起努力!

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Boletb

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值