算法—差分

1.差分的定义

对于一个给定的数组a,他的差分数组f, f [ i ] 表示 当前元素与上一个元素的差值 a [i] - a [i-1]

前缀和与差分的核⼼思想是预处理,可以在暴⼒枚举的过程中,快速给出查询的结果,从⽽优化时间 复杂度。O(1)
是经典的⽤空间替换时间的做法。
学完差分之后,⼤家会发现,前缀和与差分是⼀对互逆的运算。

2.一维差分模版

【模板】差分

解法: 

创建差分数组,然后根据差分数组的「性质」处理 次区间修改,最后还原出来原始的数组。

 

1. 创建差分数组,根据定义 f [i] = [i] − [i − 1]
也可以根据差分数组的性质 f [i] + =  [i],  [i + 1]  − =  a [i]

 

2. 根据差分数组的性质处理 q 区间修改: f [L] + =  c[R + 1] − =  c 

 

3.还原经过 q 次询问之后的 a 数组:对差分数组做⼀次「前缀和」,就可以还原出原数组 

原出原数组
由差分数组的定义得:
[1] = [1]
[2] = [2] − [1]
[3] = [3] − [2]
......
f [i] = a [i] − a [i − 1]
原数组 a 中的每⼀项:
[1] = [1]
[2] = [2] − [1] + [1] = [2] + [1]
[3] = [3] − [2] + [2] − [1] + [1] = [3] + [2] + [1]
......
a [i] = f [i] + f [i − 1] + f [i − 2] + ... + f [1]
模版代码:

 

#include<iostream>
using namespace std;

const int N = 1e5+10;
typedef long long LL;
LL n,m;
LL  a[N],f[N];

int main()
{
    cin>>n>>m;
    for(int i = 1;i <= n;i++)
    {
        int x;
        cin>>x;
        f[i] += x;
        f[i + 1] -= x;
    }
    
    LL l = 0,r = 0,k = 0;
    while(m--)
    {
        cin>>l>>r>>k;
        f[l] += k,f[r+1] -= k;
    }
    
    for(int i = 1;i <= n;i++)
    {
        a[i] = f[i] + a[i-1];
        cout<<a[i] <<" ";
    }
    return 0;
}

 

3.一维差分例题 

https://www.luogu.com.cn/problem/P3406

 解法:

先考虑如何让花费最⼩,想要求最⼩花费,需要知道每⼀段⾼铁被「乘坐了多少次」,记作 f[i],那 么最⼩花费就是「买票的花费」与「买卡的花费」两者之间的最⼩值:
买票花费: a[i] × f[i]
买卡花费,乘⻋花费 + ⼯本费: b[i] × f[i] + c[i]
那么最⼩花费就是: mincost = min(a[i] × f[i],  b[i] × f[i] + c[i]);
接下来考虑如何求出每⼀段⾼铁被「乘坐了多少次」。根据访问城市的序列p1,p2,p3,...pm可知,
对于任意⼀次访问 p i~p i+1,我们会乘坐[pi , p(i+1) -1]之间所有的⾼铁,⽐如 ,那么 pi = 3,
pi+1 = 6, [3,5] 之间所有的⾼铁都会被乘坐⼀次,相当于每个数都加上 1(注意 6位置不会乘坐到)
那么我们就可以利⽤「差分数组」:(差分数组就是解决子段同时加或减一个数的)
创建⼀个全为 0 的差分数组 f
遍历访问序列,对于每⼀次访问: [pi] + +,  [pi+1 ] − −
然后对差分数组做⼀次前缀和,就得到每个⾼铁乘坐的次数
注意城市访问的序列有可能 pi > pi+1 ,此时应该「交换」⼀下顺序

参考代码: 

#include<iostream>
using namespace std;

typedef long long LL;
const int N = 1e5+10;
LL f[N];
LL n,m;

int main()
{
    cin>>n>>m;
    int x;cin>>x;
    for(int i = 2;i <= m;i++)
    {
        int y; cin>>y;
        if(x>y)
        {
            f[y]++;
            f[x]--;
        }
        else 
        {
            f[x]++;
            f[y]--;
        }
        x = y;
    }

    for(int i = 1;i <= n;i++)
        f[i] += f[i-1];

    LL ret;
    for(int i = 1;i <= n;i++)
    {
        LL a,b,c;
        cin>>a>>b>>c;
        ret += min(f[i]*a,c+f[i]*b);
    }
    cout<<ret<<endl;
    return 0;
}

 

4.二维差分模版 

【模板】二维差分

 解法:

⼆维差分模板题,先根据差分矩阵的性质创建差分矩阵,然后根据差分矩阵的性质处理q 次区间修改,最后利⽤「前缀和」还原出来原始的矩阵。因此,重点就是差分矩阵的「性质」
可以类⽐「⼀维差分数组」的性质,推导出「⼆维差分矩阵」的性质
在差分数组中某个位置标记:表⽰后续元素统⼀被修改;
 
在差分数组中求前缀和:能够还原出原始数组。
假设我们需要将原始矩阵 中,以 (x1,y1)为左上⻆, (x2,y2)为右下⻆的⼦矩阵的每个元素都加上 k:

 

 由此可得差分矩阵的性质:

f [x1][y1] += k
f [x1][y2 + 1] −= k
f [x2 + 1][y1 ] −= k
f [x2 + 1][y2 + 1] += k
模版:
#include<iostream>
using namespace std;

typedef long long LL;
int n,m,q;
const int N = 1010;
LL f[N][N];

//差分矩阵的性质
void insert(int x1,int y1,int x2,int y2,LL k)
{
    f[x1][y1] += k;
    f[x2+1][y1] -= k;
    f[x1][y2+1] -= k;
    f[x2+1][y2+1] += k;
}

int main()
{
    cin>>n>>m>>q;
    // 预处理差分矩阵
    for(int i = 1;i <= n;i++)
        for(int j = 1;j <= m;j++)
        {
            LL x;cin>>x;
        // [i,j]为左上角,[i,j]为右上角的矩阵,统一加上x
            insert(i,j,i,j,x);
        }
    
    // 处理q次操作
    while(q--)
    {
        LL x1,y1,x2,y2,x;
        cin>>x1>>y1>>x2>>y2>>x;
        insert(x1,y1,x2,y2,x);
    }
    
    // 利用前缀和还原修改后的数组
    for(int i = 1;i <= n;i++)
    {
        for(int j = 1;j <= m;j++)
        {
            f[i][j] = f[i-1][j] + f[i][j-1] - f[i-1][j-1] + f[i][j];
            cout<< f[i][j] <<" ";
        }
        cout<<endl;
    }
    return 0;
}

遗传算法差分进化算法是两种常见的进化算法。它们在选择、交叉和变异等操作上有一些区别。 遗传算法是根据适应度值来控制父代杂交、变异后产生的子代被选择的概率值。在最大化问题中,适应值大的个体被选择的概率相应也会大一些。遗传算法首先对参数进行编码,生成初始种群,然后通过选择、交叉和变异等操作,在问题空间中搜索最优解。经典遗传算法使用适应度函数来评判每个个体性能优劣,并根据适应度值选择父代个体参与遗传操作,生成新一代种群。遗传算法的基本遗传操作包括染色体选择、染色体上基因交叉和基因变异。通过逐代优化,遗传算法不断生成新一代种群,直至满足结束条件。 差分进化算法则是采用父代差分向量生成变异向量,与父代个体向量进行交叉生成新个体向量,并直接与其父代个体进行选择。差分进化算法相对于遗传算法的逼近效果更加显著。差分进化算法通过差分向量的生成和交叉操作来扩展搜索空间,以寻找更优的解。 因此,遗传算法差分进化算法在父代个体的选择方式、新个体的生成方式以及对搜索空间的处理方式上存在差异。遗传算法更加注重根据适应度值来选择优秀的个体,而差分进化算法更加注重使用差分向量和变异操作来扩展搜索空间。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [遗传算法 差分进化算法 粒子群优化算法区别](https://blog.csdn.net/smilejiasmile/article/details/104780235)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值