震惊!递推与递归竟然可以这么编!%99的程序员都不知道!

四、归并排序(逆序对)

(一)、归并排序
归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide
and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;
即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二
路归并。
例如有8 个数据需要排序:10 4 6 3 8 2 5 7
归并排序主要分两大步:分解、合并。
合并过程为:比较a[i]和a[j]的大小,若a[i]≤a[j],则将第一个有序表中的元
素a[i]复制到r[k]中,并令i 和k 分别加上1;否则将第二个有序表中的元素a[j]复制
到r[k]中,并令j 和k 分别加上1,如此循环下去,直到其中一个有序表取完,然后再将
另一个有序表中剩余的元素复制到r 中从下标k 到下标t 的单元。归并排序的算法我们通
常用递归实现,先把待排序区间[s,t]以中点二分,接着把左边子区间排序,再把右边子区
间排序,最后把左区间和右区间用一次归并操作合并成有序的区间[s,t]。

#include //归并排序
#include
#include
#include
using namespace std;// 示例:7 5 8 15 8 45 2 5
int m[1001],r[1001];
void compare(int a,int b){
if(a==b) return;
int mid = (a+b) / 2;
compare(a,mid);
compare(mid+1,b);//这两行是我一直没有想通的,一百行for循环写的很嗨皮。。。
int qian=a,hou=mid+1,tot=a;
while(qian<=mid&&hou<=b){
if(m[qian]<=m[hou]){
r[tot] = m[qian];
tot++;
qian++;
}
else{
r[tot] = m[hou];
tot++;
hou++;
}
}
while(qian<=mid){
r[tot]=m[qian];
tot++;
qian++;
}
while(hou<=b){
r[tot]=m[hou];
tot++;
hou++;
}//这两个while不用再写if了,也比我的思路好。
for(int i=a;i<=b;i++){
m[i]=r[i];
}
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&m[i]);
}
compare(1,n);
for(int i=1;i<=n;i++){
printf("%d ",m[i]);
}
}

(二)、逆序对

上述提到归并排序是稳定的排序,相等的元素的顺序不会改变,进而用其可以解决逆序
对的问题。首先我们了解一下什么是逆序对。
逆序对:设A 为一个有n 个数字的有序集(n>1),其中所有数字各不相同。如果存
在正整数i, j 使得1 ≤ i < j ≤ n 而且A[i] > A[j],则<A[i], A[j]> 这个
有序对称为A 的一个逆序对,也称作逆序数。
例如,数组(3,1,4,5,2)的逆序对有(3,1),(3,2),(4,2),(5,2),共4 个。
所谓逆序对的问题,即对给定的数组序列,求其逆序对的数量。
从逆序对定义上分析,逆序对就是数列中任意两个数满足大的在前,小的在后的组合。
如果将这些逆序对都调整成顺序(小的在前,大的在后),那么整个数列就变的有序,即排
序。因而,容易想到冒泡排序的机制正好是利用消除逆序来实现排序的,也就是说,交换相
邻两个逆序数,最终实现整个序列有序,那么交换的次数即为逆序对的数量。
冒泡排序可以解决逆序对问题,但是由于冒泡排序本身效率不高,时间复杂度为
O(n^2),对于n 比较大的情况就没用武之地了。我们可以这样认为,冒泡排序求逆序对效
率之所以低,是因为其在统计逆序对数量的时候是一对一对统计的,而对于范围为n 的序
列,逆序对数量最大可以是(n+1)*n/2,因此其效率太低。那怎样可以一下子统计多个,
而不是一个一个累加呢?这个时候,归并排序就可以帮我们来解决这个问题。
在合并操作中,我们假设左右两个区间元素为:
左边:{3 4 7 9} 右边:{1 5 8 10}
那么合并操作的第一步就是比较3 和1,然后将1 取出来,放到辅助数组中,这个时候
我们发现,右边的区间如果是当前比较的较小值,那么其会与左边剩余的数字产生逆序关系,
也就是说1 和3、4、7、9 都产生了逆序关系,我们可以一下子统计出有4 对逆序对。接
下来3,4 取下来放到辅助数组后,5 与左边剩下的7、9 产生了逆序关系,我们可以统计
出2 对。依此类推,8 与9 产生1 对,那么总共有4+2+1 对。这样统计的效率就会大大提
高,便可较好的解决逆序对问题。
而在算法的实现中,我们只需略微修改原有归并排序,当右边序列的元素为较小值时,
就统计其产生的逆序对数量,即可完成逆序对的统计。

#include //基本完全copy上一题
#include
#include
#include
using namespace std;// 示例:7 5 8 15 8 45 2 5
int m[1001],r[1001],number=0;
void compare(int a,int b){
if(a==b) return;
int mid = (a+b) / 2;
compare(a,mid);
compare(mid+1,b);//这两行是我一直没有想通的,一百行for循环写的很嗨皮。。。
int qian=a,hou=mid+1,tot=a;
while(qian<=mid&&hou<=b){
if(m[qian]<=m[hou]){
r[tot] = m[qian];
tot++;
qian++;
}
else{
r[tot] = m[hou];
tot++;
hou++;
number += mid-qian+1;//较上一题就加了这一行,一开始还直接无脑写成了++。。。
}
}
while(qian<=mid){
r[tot]=m[qian];
tot++;
qian++;
}
while(hou<=b){
r[tot]=m[hou];
tot++;
hou++;
}//这两个while不用再写if了,也比我的思路好。
for(int i=a;i<=b;i++){
m[i]=r[i];
}
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&m[i]);
}
compare(1,n);
for(int i=1;i<=n;i++){
printf("%d “,m[i]);
}
printf(”\n%d",number);
}

走楼梯

时间限制: 1 Sec 内存限制: 128 MB
题目描述
楼梯有N 级台阶,上楼可以一步上一阶,也可以一步上二阶,编一个递推程序,计算从第
一阶走到第N 阶共有多少种不同的方法。
输入
输入一个数N(1<=N<=10)
输出
输出共有多少种方法
样例输入
4
样例输出
5
解析:
这题是简单的递推题,首先,到第1 个台阶我们有1 种方法;到第2 个台阶,我们可
以在第0 个台阶上两阶,也可以在第1 个台阶上一阶到达,即有2 种方法;对于之后第i
个台阶来说,同样的方式,可以由第i-2 个台阶上两阶,也可以由第i-1 个台阶上一阶到
达。令f[i]表示到第i 台阶的方法数,由上述分析可以得出f[i]=f[i-1]+f[i-2],初
始f[1]=1,f[2]=2,即可推得到达第n 个台阶的方法数了,复杂度O(n)。

//两种方法差不多,有手就行

#include // 走楼梯(递归)
#include
#include
#include
using namespace std;
int jisuan(int n){
if(n1) return 1;
if (n
2) return 2;
return jisuan(n-1)+jisuan(n-2);
}
int main(){
int n;
scanf("%d",&n);
printf("%d",jisuan(n));
}

#include // 走楼梯(递推)
#include
#include
#include
using namespace std;
int main(){
int n,m[101];
scanf("%d",&n);
m[1] = 1;
m[2] = 2;
for(int i=3;i<=n;i++){
m[i] = m[i-1]+m[i-2];
}
printf("%d",m[n]);
}

过河卒【NOIP2002】

时间限制: 1 Sec 内存限制: 128 MB
题目描述
棋盘上的A 点有一个过河卒,需要走到目标B 点。卒行走的规则是:可以向下、或者向右。
同时在棋盘上的任一点有一个对方的马(如C 点),对方的马所在的点和所有跳跃一步可
达的点称为对方马的控制点(如图中的C 点和P1,P2,…,P8)。卒不能通过对方马的控制
点。棋盘用坐标表示,A 点(0,0),B 点(n,m)(n,m 为不超过20 的整数),同样马的
位置坐标是需要给出的,C≠A 且C≠B。现在输入B 点和C 点的坐标,要你计算出过河卒
从A 点能够到达B 点的路径的条数。
图21 过河卒
输入
一行,4 个空格隔开的整数,表示(n,m)和C 点的坐标。
输出
过河卒从A 点能够到达B 点的路径的条数。
样例输入
4 8 2 4
样例输出
0
解析:
这题的递推思想和走楼梯的思路一样,在坐标(i,j)位置时,它可以由(i-1,j)和
(i,j-1) 点过来, 令f[i][j] 表示到达(i,j) 位置时的方案数, 那么
f[i][j]=f[i-1][j]+f[i][j-1]。当然此题稍微增加了难点,也就是有障碍点,这些
点不能达到,所以他们的方案数特殊处理为0,我们可以在一开始预处理掉。

#include // 过河卒 bug不少。。。
#include
#include
#include
using namespace std;
int main(){
int a[23][23],n,m,I,J,i,j;
scanf("%d%d%d%d",&n,&m,&I,&J);
for(i=0;i<=n;i++){
for(j=0;j<=m;j++){
a[i][j]=1;
printf("%d “,a[i][j]);
}
printf(”\n");
}
printf("\n");
if(I-1>=0&&J-2>=0) a[I-1][J-2]=0;
if(I-2>=0&&J-1>=0) a[I-2][J-1]=0;
if(I-2>=0&&J+1>=0) a[I-2][J+1]=0;
if(I-1>=0&&J+2>=0) a[I-1][J+2]=0;
if(I+1>=0&&J+2>=0) a[I+1][J+2]=0;
if(I+2>=0&&J+1>=0) a[I+2][J+1]=0;
if(I+1>=0&&J-2>=0) a[I+1][J-2]=0;
if(I+2>=0&&J-1>=0) a[I+2][J-1]=0;
a[I][J]=0;
for(i=1;i<=n;i++) if(a[i][0]) a[i][0]=a[i-1][0];
for(i=1;i<=m;i++) if(a[0][i]) a[0][i]=a[0][i-1];
for(i=0;i<=n;i++){
for(j=0;j<=m;j++){
printf("%d “,a[i][j]);
}
printf(”\n");
}
printf("\n");
for(i=1;i<=n;i++){
for(j=1;j<=m;j++){
if(a[i][j]){
a[i][j]=a[i-1][j]+a[i][j-1];
}
printf("%d “,a[i][j]);
}
printf(”\n");
}
printf("%d",a[n][m]);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/318862.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

asp.net core webApi 参数保护

Introasp.net core data protection 扩展&#xff0c;基于 IDataProtector 扩展的数据保护组件&#xff0c;自动化的实现某些参数的保护ParamsProtectionParamsProtection 是为了保护 asp.net core webapi 项目的某些参数而设计的&#xff0c;也可以用来做一定程度上的反爬虫。…

2021牛客暑期多校训练营2 J-Product of GCDs(数论+计数)

J-Product of GCDs Code1 对于每个质数以及每个质数的次幂单独考虑他们的贡献&#xff0c;由于多次使用快速幂导致TLE #include<bits/stdc.h> using namespace std; using lllong long; template <class Tint> T rd() {T res0;T fg1;char chgetchar();while(!is…

AT2390-[AGC016F]Games on DAG【状压dp,SG函数】

正题 题目链接:https://www.luogu.com.cn/problem/AT2390 解题思路 nnn个点的DAGDAGDAG&#xff0c;mmm条边可有可无&#xff0c;111和222上有石头。求有多少种方案使得先手必胜。 1≤n≤15,1≤m≤n(n−1)21\leq n\leq 15,1\leq m\leq \frac{n(n-1)}{2}1≤n≤15,1≤m≤2n(n−1…

牛客题霸 [合并两个有序的数组] C++题解/答案

牛客题霸 [合并两个有序的数组] C题解/答案 题目描述 给出两个有序的整数数组 和 &#xff0c;请将数组 合并到数组 中&#xff0c;变成一个有序的数组 注意&#xff1a; 可以假设 数组有足够的空间存放 数组的元素&#xff0c; 和 中初始的元素数目分别为 和 题目描述 给出…

震惊!快速幂怎么编?省一说暴力,银牌说递归,国集听完笑了

国集&#xff1a;打表啊&#xff01;&#xff01; 题目描述 给你三个整数 b,p,kb,p,kb,p,k&#xff0c;求 bp mod kb^p \bmod kbpmodk。 输入格式 输入只有一行三个整数&#xff0c;分别代表 b,p,kb,p,kb,p,k 输出格式 输出一行一个字符串 b^p mod ks&#xff0c;其中 b,…

CF1392G-Omkar and Pies【dp】

正题 题目链接:https://www.luogu.com.cn/problem/CF1392G 题目大意 两个长度为kkk的起始和目标01串。 nnn个操作交换起始串的两个位置&#xff0c;选择一段长度至少为mmm的连续操作序列使得相同的位数最多。 1≤m≤n≤106,1≤k≤201\leq m\leq n\leq 10^6,1\leq k\leq 201≤…

codeforces1484 B. Restore Modulo(数学)

B. Restore Modulo 忘了当时怎么乱搞的了~ #include<bits/stdc.h>using namespace std; using lllong long;constexpr int N200010;int n; ll a[N],d[N],d0[N]; int main() {ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);int T1;cin>>T;whil…

牛客题霸 [反转字符串] C++题解/答案

牛客题霸 [反转字符串] C题解/答案 题目描述 写出一个程序&#xff0c;接受一个字符串&#xff0c;然后输出该字符串反转后的字符串。&#xff08;字符串长度不超过1000&#xff09; 题解&#xff1a; 有reverse现成的翻转函数&#xff0c;直接套进去就可以 如果不用函数的…

新汉诺塔(洛谷P1242)含第11个数据的解决办法

解析 应该从大到小一个个移&#xff0c;这样后面大盘就可以直接忽略&#xff0c;保证没有冗余操作&#xff0c;必定最优&#xff08;如果先移动小的&#xff0c;后面移动大的时还要动小的&#xff09; 对于第id个从当前位置到目标的移动有两种移动方案&#xff1a; 法1&#x…

让 .Net 更方便的导入导出Excel

Intro因为前一段时间需要处理一些 excel 数据&#xff0c;主要是导入/导出操作&#xff0c;将 Excel 数据转化为对象再用程序进行处理和分析&#xff0c;没有找到比较满意的库&#xff0c;于是就自己造了一个轮子&#xff0c;屏蔽掉了 xlsx 与 xls 的差别&#xff0c;屏蔽了 Np…

P7115-[NOIP2020]移球游戏【构造】

正题 题目链接:https://www.luogu.com.cn/problem/P7115 题目大意 n1n1n1个柱子&#xff0c;前面nnn个上面各有mmm个球&#xff0c;球有nnn种颜色&#xff0c;每种mmm个。 你每次可以把一个柱子最上面的球放到另一个上面&#xff0c;要求在820000820000820000次内使得同种颜色…

2021牛客暑期多校训练营1 I-Increasing Subsequence(期望dp+优化)

I-Increasing Subsequence fi,j,0/1f_{i,j,0/1}fi,j,0/1​表示上一轮第一个人选了iii&#xff0c;第二个人选了jjj&#xff0c;并且当前是第1/2个人选择的概率。 转移考虑枚举k下一步往哪走 fi,k,1∑fi,j,0/cntf_{i,k,1}\sum f_{i,j,0}/ \text{cnt}fi,k,1​∑fi,j,0​/cnt fk,…

牛客题霸 [子数组的最大累加和问题] C++题解/答案

牛客题霸 [子数组的最大累加和问题] C题解/答案 题目描述 给定一个数组arr&#xff0c;返回子数组的最大累加和 例如&#xff0c;arr [1, -2, 3, 5, -2, 6, -1]&#xff0c;所有子数组中&#xff0c;[3, 5, -2, 6]可以累加出最大的和12&#xff0c;所以返回12. [要求] 时间复…

无限序列 (ybtoj C.3)

解析 乍一看很蒙的题 首先&#xff0c;a-b1的个数可以等价于**&#xff08;1-b&#xff09;1的个数减去&#xff08;1-a-1&#xff09;1的个数** 分析之后发现&#xff0c;经过多次变换后&#xff1a; 长度 1的个数 1 1 2 1 3 2 5 3 8 5 … … 又是熟悉的斐波拉契。。。 但是我…

P5644-[PKUWC2018]猎人杀【NTT,分治】

正题 题目链接:https://www.luogu.com.cn/problem/P5644 题目大意 nnn个人&#xff0c;每个人被选中的权重是aia_iai​。每次按照权重选择一个没有死掉的人杀死&#xff0c;求第111个人最后死的概率。输出答案对998244353998244353998244353取模。 wi>0,∑i1nwi≤105w_i>…

对传统应用进行容器化改造

本文由 陈计节 翻译自 FP Complete 网站上的文章 CONTAINERIZING A LEGACY APPLICATION: AN OVERVIEW&#xff0c;原作者 Emanuel Borsboom。以下为译文全文&#xff0c;如需阅读英文原文&#xff0c;请转到文末获取链接&#xff1a;本文接下来简要介绍什么是容器化&#xff0c…

2021牛客暑期多校训练营2 L-WeChat Walk(分块)

L-WeChat Walk 每个大点记录一下邻接点的最大步数 每次修改的时候&#xff0c;枚举修改点的邻接的大点来更新 修改大点的时候直接判是不是比邻接点都大 代码抄的std好不容易才看懂~ Code1 #include<bits/stdc.h> using namespace std; template <class Tint> T…

牛客题霸 [求平方根] C++题解/答案

牛客题霸 [求平方根] C题解/答案 题目描述 实现函数 int sqrt(int x). 计算并返回x的平方根 题解&#xff1a; 要求返回平方根&#xff0c;我们就找一个i&#xff0c;使得ii<x&&(i1)(i1)>x 这样的i就是我们要找的答案 注意&#xff0c;x有可能为负数&#xf…

二分算法:平均值(洛谷 UVA1451)

解析 这道题寻找平均值的max&#xff0c;答案明显具有单调性&#xff0c;所以采用二分算法 从0到1不断取中点mid作为平均值的可能点&#xff0c;看是否存在不短于l的数列均值&#xff1e;mid不难得到以下代码&#xff1a; double st0,ed1;for(int i1;i<10;i){double mid(s…

P5287-[HNOI2019]JOJO【KMP】

正题 题目链接:https://www.luogu.com.cn/problem/P5287 题目大意 开始一个空串&#xff0c;nnn个操作 在末尾加入xxx个ccc字符&#xff08;保证和ccc和前面的字符不同&#xff09;返回到第xxx次操作之后 每次操作完成后求所有前缀的最长的borderborderborder长度和 1≤n≤…