ACM算法训练——枚举与贪心2

枚举与贪心2

1.差分、前缀和;对称

前缀和:数组前n个数之和sum[i]=sum[i-1]+a[i];

差分:差分数组 delta[i]表示第i个数-第i-1个数的差值 delta[i]=a[i]-a[i-1];约定delta[0]=0;则,delta[1]=a[1]-a[0]=a[1]-0=a[1];

都可用来复原原数组,
对sum[i],对前缀数组,求差分得原数组
a[i]=sum[i]-sum[i-1];

对delta[i],对差分数组,求前缀和得原数组
a[i]=delta[i]+delta[i-1]+delta[i-2]+…+delta[1];

实际运用

校门外的树
校门口一排树,从0开始的数轴,树所在区域长度为L,数轴上的每个整数点,即0,1,2,……,L,都种有一棵树,现用m个区域建地铁,建地铁处都不能种树,每个区域包含地标用区域 [a,b] 表示。
计算建完地铁后,剩下的树有多少棵?
在这里插入图片描述

思路1(最直接)
设置flag[L+1]标记数组,初始为0,标记树都在,初始树的数目count=L+1;一旦建地铁区域i∈[a,b],遍历判断如果flag[i]不为1(树还在)则设置flag[i]为1,表示树不在了,并count–,拔除该树。最后输出count的值。

差分数组应用

思路2(利用差分数组,求解原数组)
将问题转化为求解[0,L]数轴区域各个点被地铁覆盖的次数
1.设置差分数组delta[L+1],初始化为0表示都为被地铁覆盖。
根据差分数组定义,在读到覆盖区域时,只需要将区域左端点delta[a]++;将区域右端点b,delta[b+1]- -;
【差分数组定义为delta[i]=a[i]-a[i-1];易知,[a,b]区域原数组值加1,则对差分数组而言,左端点处差分数组值 = 该端点处数值 – 前一端点数值 = 1,因此delta[a]++;
(a,b]处,该区域原数组值均加1,即delta[i]的值均为0,在b+1端点处,delta[b+1]=s[b+1]-s[b],显然区域b+1处未加1,因此比原来少1,delta[b+1] - -】
2.求解原数组,若s[i]=0,表示一次也没覆盖——有树在
根据差分数组,求解原数组,即求差分数组的前缀和。s[i]=delta[0]+delta[1]+…+delta[i];
循环遍历从0到L,s+=delta[i];判断s==0否,为0则count++;最后输出count的值。

并集

思路3(地铁区域并集)
将所有建地铁区域有交集的合并。
定义地铁区域结构体,包含左右端点。按左端点所在位置排序,依次两两比较合并交集。
用总数目count=L+1减去各合并后区域左右端点所包含的树的数目y-x+1; count-=(y-x+1) ;最后再单独减去最后一个区域的树,即是结果count

在这里插入图片描述
上面两种方法的综合———差分数组

思路4(只关注差分数组,未建数轴)
将只包含地铁区域两端点的差分数组定义为结构体,结构体关键字包含,差分数组端点所在位置下标以及差分数组执行的操作+1或–1。
按下标大小对差分数组进行排序
求端点处对应原数组值,关注原数组从0变成1的端点,count+=delta[i].index-delta[i-1].index;
对最后一段求解,count+=l-delta[2*m].index+1;

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值