2021-08-18

2021授课

面向大众

1.递归

递归

三要素:

  • 这个函数是干什么的
  • 递归结束条件是什么(就是找特殊的)
  • 找出函数的等价关系

例子:

1.求n的阶乘

函数是干什么的?定义函数int f( int n ) 表示求n的阶乘,

递归结束条件? n等于1时,返回1嘞,n等于2时,返回2嘞 ( n <= 2 就返回 n本身 )

函数等价关系? f(n) = n * f(n-1)

10!=1*2*3*4*5*6*7*8*9*10
9! =1*2*3*4*5*6*7*8*9
  
发现:10! = 10 * 9!
    函数关系 f(10) = 10 * f(9)
    对应n的关系: f(n) = n * f(n-1)

2.斐波那锲数列, 求这个数列的第n项

函数是干什么的? 定义函数int f( int n ) 表示求第n项

递归结束条件? n等于1或者n等于2时 返回 都是 1

函数等价关系? f(n) = f(n-1) + f(n-1)

1 2 3 4 5 6 7  8  9  10 11 12  13  14
1 1 2 3 5 8 13 21 34 55 89 144 233 377.............
    从第三项开始,第n项是第n-1项 + 第n-2项
    f(n) = f(n-1) + f(n-2)
#include <iostream>
using namespace std;

int f( int n )
{
	if ( n <= 2 ) {
		return 1;
	}
	
	return f(n-1) + f(n-2);
}

int main()
{
	int n;

	for ( int i = 1; i <= 41; ++i ) {
		cout << "第" << i << "项" << f(i) << '\n';
	}

	return 0;
}

递归优化

1.考虑是否重复计算

2.是否可以自底向上解决问题 (递推)

题目实战

⼀只青蛙⼀次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上⼀个n级的台阶总共有
多少种跳法。

函数是干什么的? 定义函数int f( int n ) 表示青蛙跳到第n级台阶的跳法种数

递归结束条件? n<=0时,结果为0 ; n == 1 时,结果为1 ; n == 2 时,结果为2;

函数等价关系? 青蛙跳到第n级台阶,可以从第n-1级直接跳1级上去,也可以从n-2级台阶直接跳2级上去

得出函数关系式: f(n) = f(n-1) + f(n-2);

#include <iostream>
using namespace std;

int f( int n )
{
	if ( n <= 0 ) {
		return 0;
	}
    else if ( n == 1 ) {
        return 1;
    }
    else if ( n == 2 ) {
        return 2;
    } 
	return f(n-1) + f(n-2);
}

int main()
{
	int n;
	cin >> n;
	cout << "青蛙跳到第" << n << "级台阶的跳法:" << f(n) << endl;

	return 0;
}
#include <iostream>
using namespace std;
int a[1005];

int f( int n )
{
	if ( n <= 0 ) {
		return 0;
	}
	else if ( a[n] ) {
		return a[n];
	}
	else if ( n == 1 ) {
		return a[n] = 1;
	}
	else if ( n == 2 ) {
		return a[n] = 2;
	}
	return a[n] = f(n-1) + f(n-2);
	
}

int main()
{
	int n;
	cin >> n;
	f(n);
	cout << "青蛙跳到第" << n << "级台阶的跳法:" << a[n] << endl;

	return 0;
}
⼀个机器⼈位于⼀个 m x n ⽹格的左上⻆ (起始点在下图中标记为“Start” )。
机器⼈每次只能向下或者向右移动⼀步。机器⼈试图达到⽹格的右下⻆(在下图中标记为“Finish”)。
问总共有多少条不同的路径?

在这里插入图片描述

函数是干什么的? 定义函数int f( int x, int y ) 表示机器人走到此坐标的路径数

递归结束条件? x==1&&y!=1 结果为1;同理,x!=1&& y ==1时,结果同样为1

函数等价关系? 机器人走到(x,y) 可以从 (x-1,y) 或者 (x, y-1)这两个坐标走过来,

得出函数关系式: f(x, y) = f(x-1, y) + f(x, y-1);

#include <iostream>
using namespace std;

int f( int x, int y );

int main()
{
	int n, m;
	cin >> n >> m;
	cout << "走法的种数:" << f(n, m);
	return 0;
}

int f( int x, int y )
{
	if ( (x == 1 && y != 1) || ( y == 1 && x != 1 ) ) {
		return 1;
	}
	return f(x-1, y) + f(x, y-1);
}
#include <iostream>
using namespace std;

const int N = 1e4+5;
int dp[N][N];

int f( int x, int y );

int main()
{
	int n, m;
	cin >> n >> m;
	cout << "走法的种数:" << f(n, m);
	return 0;
}

int f( int x, int y )
{
	if ( dp[x][y] ) {
		return dp[x][y];
	}

	if ( (x == 1 && y != 1) || ( y == 1 && x != 1 ) ) {
		return dp[x][y] = 1;
	}

	return dp[x][y] = f(x-1, y) + f(x, y-1);
}

题目:2^n * 2^n的矩阵,初始全为1,现在修改,改为每个左上角小矩阵全为0,

#include <iostream>
using namespace std;

const int N = 1025;
int s[N][N], n, b = 1;

void f( int l, int x, int y )
{
	if ( l == 2 ) {
		s[x][y] = 0;
		return ;
	}
	for ( int i = x; i <= x+l/2-1; ++i ) {
		for ( int j = y; j <= y+l/2-1; ++j ) {
			s[i][j] = 0;
		}
	}
	f(l/2, x+l/2, y);
	f(l/2, x+l/2, y+l/2);
	f(l/2, x, y+l/2);
}

int main()
{
	cin >> n;
	for ( int i = 1; i <= n; ++i ) {
		b *= 2;
	}
	for ( int i = 1; i <= b; ++i ) {
		for ( int j = 1; j <= b; ++j ) {
			s[i][j] = 1;
		}
	}
	f(b, 1, 1);
	for ( int i = 1; i <= b; ++i ) {
		for ( int j = 1; j <= b; ++j ) {
			cout << s[i][j] << ' ';
		}
		cout << '\n';
	}
	
	return 0;
}

2.搜索/遍历

深度优先

深度优先遍历
深度优先遍历主要思路是从图中⼀个未访问的顶点 V 开始,沿着⼀条路⼀直⾛到底,然后从这条路尽头
的节点回退到上⼀个节点,再从另⼀条路开始⾛到底...,不断递归重复此过程,直到所有的顶点都遍历
完成,它的特点是不撞南墙不回头,先⾛完⼀条路,再换⼀条路继续⾛

例子:n的全排列

3

123 132 213 231 312 321

在这里插入图片描述

#include <iostream>
using namespace std;

int n;
int num[20], sign[20];

//此函数表示往第now个盒子里面放数字
void dfs( int now )
{
	if ( now == n+1 ) {
		for ( int i = 1; i <= n; ++i ) {
			cout << num[i];
		}
		cout << '\n';
		return ;
	}
	
	for ( int i = 1; i <= n; ++i ) {
		if ( !sign[i] ) {
			sign[i] = 1;
			num[now] = i;
			//表示往第now+1个盒子里面放数字,即进入下一步
			dfs(now+1);
			sign[i] = 0;
		}
	}
}

int main()
{
	cin >> n;
	dfs(1);
	return 0;
}

迷宫问题

给定n*m的矩阵迷宫,起点x,y, 终点x1,y1,求出起点到终点的最短距离
每次只能有上下左右四个方向可以走,矩阵为1表示这是障碍物不能通过。

5 4  五行四列
0 0 1 0 /*
0 0 0 0
0 0 1 0
0 1 0 0
0 0 0 1  这是迷宫*/
1 1 4 3  // 这是起点终点

输出:7
 

在这里插入图片描述

#include <iostream>

using namespace std;

//矩阵数组,标记数组
int n, m, mi[10][10], sign[10][10];
int x, y, x1, y1, mins = 0x3f3f3f3f;
//方向
int direct[4][2] = {
	{-1,0},{0,1},{1,0},{0,-1}
};

void dfs( int l, int r, int step )
{
	if ( l == x1 && r == y1 ) {
		mins = min(mins, step);
	}
	
	for ( int i = 0; i < 4; ++i ) {
		int tx = l + direct[i][0];
		int ty = r + direct[i][1];
		
		if ( mi[tx][ty] == 1 || tx < 1 ||
			 ty < 1 || tx > n || ty > m
		 	|| sign[tx][ty] ) {
			continue;
		}
		else {
			sign[tx][ty] = 1;
			dfs(tx, ty, step+1);
			sign[tx][ty] = 0;
		}
	}
}

int main()
{
	cin >> n >> m;
	for ( int i = 1; i <= n ; ++i ) {
		for ( int j = 1; j <= m; ++j ) {
			cin >> mi[i][j];
		}
	}
	cin >> x >> y >> x1 >> y1;
	
	sign[x][y] = 1;
	dfs(x, y, 0);
	
	cout << mins << endl;
	return 0;
}

广度优先

⼴度优先遍历,指的是从图的⼀个未遍历的节点出发,先遍历这个节点的相邻节点,再依遍次历每个相邻节点的相邻节点。

树的层序遍历

接上一讲迷宫问题:

现在用广度优先来解决问题:

在这里插入图片描述

#include <iostream>
#include <queue>
using namespace std;

//矩阵数组,标记数组
int n, m, mi[10][10], sign[10][10];
int x, y, x1, y1, mins = 0x3f3f3f3f;
//方向
int direct[4][2] = {
	{-1,0},{0,1},{1,0},{0,-1}
};

typedef struct{
	int l, r, step;
}Node;

void bfs()
{
	queue<Node> q;
	Node node = {x, y, 0};
	q.push(node);
	
	while ( !q.empty() ) {
		Node temp = q.front();
		for ( int i = 0; i < 4; ++i ) {
			int tx = temp.l + direct[i][0];
			int ty = temp.r + direct[i][1];
			
			if ( mi[tx][ty] == 1 || tx < 1 ||
			 	ty < 1 || tx > n || ty > m
		 		|| sign[tx][ty] ) {
				continue;
			}
			
			else {
				sign[tx][ty] = 1;
				Node t = { tx, ty, temp.step+1};
				if ( tx == x1 && ty == y1 ) {
					mins = min(mins, t.step);
				}
				q.push(t);
			}
		}
		q.pop();
	}
}

int main()
{
	cin >> n >> m;
	for ( int i = 1; i <= n ; ++i ) {
		for ( int j = 1; j <= m; ++j ) {
			cin >> mi[i][j];
		}
	}
	cin >> x >> y >> x1 >> y1;

	sign[x][y] = 1;

	bfs();

	cout << mins << endl;
	return 0;
}

图的邻接矩阵存储与遍历

用一个n*n的矩阵表示两个顶点之间的关系

例如:2 -> 3 m[2] [3] = 1, 如果是无向图,只需要反过来存一遍即可,如果边还带有权值,只需要把权值存起来即可

##无向图
输入一个n,表示图的定点数,从1开始计数,
输入一个m,表示边,
输出:遍历序列

5 4
1 2
3 4
2 3
1 5

在这里插入图片描述

#include <iostream>

using namespace std;

const int N = 1e3+5;
int m[N][N], n, k;//n个顶点,k条边
int sign[N];

void dfs( int now )
{
	cout << now << ' ';
	sign[now] = 1;
	
	for ( int i = 1; i <= n; ++i ) {
		if ( m[now][i] && !sign[i] ) {
			sign[i] = 1;
			dfs(i);
		}
	}
}

int main()
{
	int s, e;
	cin >> n >> k;
	for ( int i = 1; i <= k; ++i ) {
		cin >> s >> e;
		m[s][e] = 1;
		m[e][s] = 1;
	}
	
	dfs(1);
	
	return 0;
}
#include <iostream>
#include <queue>
using namespace std;

const int N = 1e3+5;
int m[N][N], n, k;//n个顶点,k条边
int sign[N];

void bfs()
{
	queue<int> q;
	q.push(1);
	sign[1] = 1;
	while( !q.empty() ) {
		int temp = q.front();
		cout << temp << ' ';
		for ( int i = 1; i <= n; ++i ) {
			if ( m[temp][i] && !sign[i] ) {
				q.push(i);
				sign[i] = 1;
			}
		}
		q.pop();
	}
}

int main()
{
	int s, e;
	cin >> n >> k;
	for ( int i = 1; i <= k; ++i ) {
		cin >> s >> e;
		m[s][e] = 1;
		m[e][s] = 1;
	}

	bfs();

	return 0;
}

思考题:

提示:这章讲的是搜索,肯定是希望你们用搜索解出来啦。。。long long

在这里插入图片描述

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

3.位运算

整数、二进制

>>右移
<<左移
&按位与
|按位或
~取反
^按位异或(支持交换律) abc^d = acd^b

右移>>,左移<<

>> <<:( 这里假设只有三位 )	二进制位都向右边移动n位(n是运算符右边的数字),左边不够补0;    例如:4->二进制100  ==>  4>>1(表示4对应的二进制位向右移动一位) ==> 010            左移:理解同右移    例如:4->二进制100  ==>  4<<1(表示4对应的二进制位向左移动一位) ==> 000

基本的四种位运算

以下都假设只有四位二进制

&:二进制位对应,都为1时,结果才为1(可以理解为且,且只有都为1时结果才为1)    例如:9->二进制1001  10->二进制1010   1->二进制0001   0->二进制0000    9&1:            1001          & 0001       等于:0001                    9&10:			1001          & 1010           等于:1000                |:按位或   对应二进制,都为0时结果才为0;^:按位异或  对应二进制,相同为0,不同为1;说明一个整数与自身异或得0,一个整数与0异或得自身~:取反, 自己的二进制,1变为0,0变为1;

题目演练:

1.判断奇偶

/*	给你一个整数,判断奇偶	用n&1 ==1就是奇数,反之就是偶数*/#include <iostream>using namespace std;int main(){    int n;    cin >> n;    if ( n & 1 ) {        cout << "这是奇数" << endl;    }    else {        cout << "这是偶数" << endl;    }	return 0;}

2.翻转数字

/*给定一个十进制整数,输出它在二进制下的翻转结果。Input: 43261596 (00000010100101000001111010011100)Output: 964176192 (00111001011110000010100101000000)*/#include <iostream>using namespace std;int main(){    int n;    int ans = 0;    cin >> n;    for ( int i = 0; i < 32; ++i ) {        ans <<= 1;        ans += ( n & 1 );		n >>= 1;    }    cout << ans << endl;    return 0;}

3.找不重复的

/*	给定一个整数数组,这个数组里只有一个数次出现了一次,其余数字出现了两次,求这个只出现一次的数字。Input: 5  4 1 2 1 2Output: 4用异或运算*/#include <iostream>using namespace std;int main(){    int n, a[105], ans = 0;    cin >> n;    for ( int i = 0; i < n; ++i ) {        cin >>a[i];    }    for ( int i = 0; i < n; ++i ) {        ans ^= a[i];    }    cout << ans << endl;    return 0;}

4.跟第三题类似

/*	给一个整数n,输入n+1个数字,这些数字在1~n的范围内,并且这n+1个数字中只有一对重复的数字,请找出重复的数字	5	1 2 3 3 4 5		3*/#include <iostream>using namespace std;int main(){    int n, num, ans = 0;    cin >> n;    for ( int i = 0; i <= n; ++i ) {        cin >> num;        ans ^= num;    }    for ( int i = 1; i <= n; ++i ) {        ans ^= i;    }    cout << ans <<'\n';    return 0;}

在这里插入图片描述

/*输入:1314520  输出:249036820*/#include <iostream>#include <cstdio>using namespace std;int main(){	unsigned int n;	scanf("%u", &n);	printf("%u\n", (n >> 16) + (n << 16));	return 0;}

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

4.前缀和与差分

前缀和:

题目:(一维)

前缀和是一种重要的预处理,能大大降低查询的时间复杂度

给定一个有n个整数的数组,对这这个数组进行m次查询,输出每次查询l到r区间([l,r])的所有数字的和例如:5 21 2 3 4 51 32 4输出:69
/*原数组num[n]重新定义一个数组a[n],a[i]表示num数组从下标1到n所有数字的和a[0] = 0 ( num[0] );a[1] = num[1];a[2] = num[1] + num[2];a[3] = num[1] + num[2] + num[3];a[4] = num[1] + num[2] + num[3] + num[4];......................*/结论查询[l,r] 只需要a[r]-a[l-1]即可!!!!!!!!!!!!!!!!
#include <iostream>

using namespace std;
int n, m, a[105], num[105];

int main()
{
	cin >> n >> m;
	for ( int i = 1; i <= n; ++i ) {
		cin >> num[i];
		a[i] = a[i-1] + num[i];
	}
	
	while (m--) {
		int l ,r;
		cin >> l >> r;
		cout << a[r] - a[l-1] << '\n';
	}
	
	return 0;
}

题目(二维)

二维查询

输入一个n*n的矩阵,数组数字在-100~100之间,n<=100,

进行m次查询,每次查询(i,j)为左上角,(x,y)为右下角的子阵的所有元素的和;

例如:

4 1 (4*4矩阵,查询1次)
    
0 -2 -7 0
 9 2 -6 2
-4 1 -4  1 
-1 8  0 -2(输入的矩阵)

1 1 2 2  (查询1,1为左上角,2,2为右下角矩阵的里面所有元素和)
    
输出:9 
//代码/*4 10 -2 -7 0 9 2 -6 2-4 1 -4  1 -1 8  0 -21 1 2 2 */#include <iostream>using namespace std;int n, m;int num[105][105], a[105][105];int main(){	cin >> n >> m;	for ( int i = 1; i <= n; ++i ) {		for ( int j = 1; j <= n; ++j ) {			cin >> num[i][j];			a[i][j] = a[i-1][j] + a[i][j-1] - a[i-1][j-1] + num[i][j];		}	}		while ( m-- ) {		int i, j, x, y;		cin >> i >> j >> x >> y;		int temp = a[x][y] - a[i-1][y] - a[x][j-1] + a[i-1][j-1];		cout << temp << '\n';	}	return 0;}

在这里插入图片描述

题目:最大子阵和

在这里插入图片描述

输入n*n的矩阵,输出最大子阵的和;

/*
4
0 -2 -7 0
 9 2 -6 2
-4 1 -4  1 
-1 8  0 -2

15
*/
    
#include <iostream>
using namespace std;

int n, a[122][122];


int main()
{
	int num, maxn = -0x3f3f3f3f, temp;
	cin >> n;
	for ( int i = 1; i <= n; ++i ) {
		for ( int j = 1; j <= n; ++j ) {
			cin >> num;
			a[i][j] = a[i-1][j] + a[i][j-1] + num - a[i-1][j-1];
		}
	}
	for ( int i = 1; i <= n; ++i ) {
		for ( int j = 1; j <= n; ++j ) {
			for ( int x = i; x <= n; ++x ) {
				for ( int y = j; y <= n; ++y ) {
					temp = a[x][y] - a[x][j-1] - a[i-1][y] + a[i-1][j-1];
					maxn = max(maxn, temp);
				}
			}
		}
	}

	
	cout << maxn << endl;
	
	return 0;
}

差分:

一般用于区间里面的元素同时修改。

例子:给定一个有n个数的整数数组,对他进行m次修改,每次修改都是使[l,r]区间的所有元素都加一,

求m次操作后的数组序列。

例如原数组a为:1 3 1 4 5 2 0

对它进行3次修改:[1,5] [2,4] [3,3];

新数组a1:2 5 4 6 6 2 0

从下标1开始,现在我们构建这样一个数组:c[n],原数组用a[n]表示;c[i]表示a[i]-a[i-1],c[1]=a[1],总结来说,c数组存的就是原数组相邻元素的差

c数组: 1 2 -2 3 1 -3 -2

再来看一下,对c数组求一下他的前缀和!!!!

为什么差分数组的前缀和是原数组?

c[i] = a[i] - a[i-1];

c[1] = a[1];
c[2] = a[2] - a[1];
c[3] = a[3] - a[2];
c[4] = a[4] - a[3];
c[5] = a[5] - a[4];
c[6] = a[6] - a[5];

c[1]+c[2] = a[1] + a[2] - a[1] = a[2];
c[1]+c[2]+c[3] = a[1] + a[2] - a[1] + a[3] - a[2] = a[3];
...........................

区间修改怎么来维护呢?

例如原数组a为:1  3  1   4  5   2  0    差分c数组   :1  2  -2  3  1  -3  -2 对原数组进行3次修改:  [1,5]第一次修改:2 4 2 5 6 2 0 上次差分数组:	1  2  -2  3  1  -3  -2 差分c数组:		 2  2  -2  3  1  -4  -2    [2,4]第二次修改:2 5 3 6 6 2 0 上次差分数组:	2  2  -2  3  1  -4  -2差分c数组:		 2  3  -2  3  0  -4  -2    [3,3]第三次修改:2 5 4 6 6 2 0 上次差分数组:	2  3  -2  3  0  -4  -2 差分c数组:		 2  3  -1  2  0  -4  -2结论:对[l,r]区间修改时,差分数组c[l] +(-) 1,  c[r+1] -(+) 1;

代码:


差分题目实战:

小IT接到一个任务,摆在小IT面前的是 n 个空瓶,小it会收到 k 条命令,命令都是"A B"的形式,意思是要小IT往范围为A...B的空瓶里放一枚金币,例如:如果命令是7 9,那么小IT要往第7,8,9个空瓶里放一枚金币。在小IT完成所有命令后,需要给上司发送一条信息,表示这 n 个瓶子所装金币的中位数是多少。输入格式:第一行包含一个整数 n(1≤n≤106),表示瓶子的数量。第二行包含一个整数 k(1≤k≤104), 表示命令的数量。后面 k 行,每行两个整数A B(1≤A≤B≤n),表示命令的内容。输出格式:输出一个整数,n个瓶子所装金币的中位数是多少。保证 n 为奇数,中位数是唯一的。输入样例:745 52 44 63 5输出样例:1样例解释:完成k次操作后,空瓶里金币的数量为[0,1,2,3,3,1,0]。 即[0,0,1,1,2,3,3],其中位数为1。
#include <iostream>#include <algorithm>using namespace std;const int N = 1e6+5;int c[N], n, m, y[N];int s, e;int main(){	cin >> n >> m;	while (m--) {		cin >> s >> e;		c[s]++;		c[e+1]--;	}		for ( int i = 1; i <= n; ++i ) {		y[i] = y[i-1] + c[i];	}		sort(y+1, y+n+1);//	for ( int i = 1; i <= n; ++i ) {//		cout << y[i] << " ";//	}//	cout << endl;	cout << y[(n>>1)+1] << endl;		return 0;}
在n*n的矩阵中,初始元素全为0,对它进行m次操作,求操作完成后的矩阵;输入格式第一行,两个正整数 n,m。意义如题所述。接下来 m 行,每行两个坐标 (x1,y1)和 (x2,y2),代表一次操作,左上角是 (x1,y1)右下角是 (x2,y2),对这个区域全部加一。输出矩阵输入5 32 2 3 33 3 5 51 2 1 4输出0 1 1 1 00 1 1 0 00 1 2 1 10 0 1 1 10 0 1 1 1
#include <iostream>using namespace std;int n, m;int q[1002][1002], answer[1002][1002];int main(){	int x1, y1, x2, y2;	cin >> n >> m;	for ( int i = 1; i <= m; ++i ) {		cin >> x1 >> y1 >> x2 >> y2;		for ( int i = x1; i <= x2; ++i ) {			q[i][y1] += 1;			q[i][y2+1] -= 1;		}	}	int sum;	for ( int i = 1; i <= n; ++i ) {		sum = 0;		for ( int j = 1; j <= n; ++j ) {			sum += q[i][j];			answer[i][j] = sum;		}	}	for ( int i = 1; i <= n; ++i ) {		for ( int j = 1; j <= n; ++j ) {			cout << answer[i][j] << ' ';		}		cout << '\n';	}	return 0;}

5.高等排序

归并排序:

对数组进行分组,然后将两个有序数组合并,这期间需要用到一个临时数组用来过渡。所以会有O(n)的空间复杂度,

先分再合!

输入:
6
3 2 6 5 9 4

输出:
2 3 4 5 6 9

要求使用归并排序

先分:(如果分的组只有一个元素了,则默认就是有序的)

见如下图片:

在这里插入图片描述

再合

见如下图片:

在这里插入图片描述
在这里插入图片描述

合并两个有序数组:

#include <iostream>
#include <algorithm>
using namespace std;

const int N = 105;
int a[N], b[N], c[220];
int n, m;

int main()
{
	cin >> n;
	for ( int i = 0; i < n; ++i ) {
		cin >> a[i];
	}
	cin >> m;
	for ( int i = 0; i < m; ++i ) {
		cin >> b[i];
	}
	//保证两个数组有序
	sort(a, a+n), sort(b, b+m);
	
	//合并
	int i = 0, j = 0, k = -1;
	while ( i < n && j < m ) {
		if ( a[i] <= b[i] ) {
			c[++k] = a[i];
			++i;
		}
		else {
			c[++k] = b[j];
			++j;
		}
	}
	
	while ( i < n ) {
		c[++k] = a[i];
		++i;
	}
	
	while ( j < m ) {
		c[++k] = b[j];
		++j;
	}
	
	//输出:
	cout << "a数组:";
	for ( int i = 0; i < n; ++i ) {
		cout << a[i] << ' ';
	}
	cout << '\n';
	
	cout << "b数组:";
	for ( int i = 0; i < m; ++i ) {
		cout << b[i] << ' ';
	}
	cout << '\n';
	
	cout << "c数组:";
	for ( int i = 0; i < n+m; ++i ) {
		cout << c[i] << ' ';
	}
	cout << '\n';
	return 0;
}

完整代码:

#include <iostream>using namespace std;const int N = 10e7;int num[N];//归并排序static int tmp[N];void merge_sort( int q[], int l, int r ){	if ( l >= r ) return;		int mid = l + r >> 1;		merge_sort(q, l, mid);	merge_sort(q, mid + 1, r );		int k = 0, i = l, j = mid + 1;	while ( i <= mid && j <= r ) {		if ( q[i] <= q[j] ) {			tmp[k++] = q[i++];		}		else {			tmp[k++] = q[j++];		}	}	while ( i <= mid ) tmp[k++] = q[i++];	while ( j <= r ) tmp[k++] = q[j++];		for ( i = l, j = 0; i <= r; ++i, ++j ) {		q[i] = tmp[j];	}}int main(){    int n;    cin >> n;    for ( int i = 0; i < n; ++i ) {		cin >> num[i];	}	//归并排序	merge_sort(num, 0, n-1);    	for ( int i = 0; i < n; ++i ) {		cout << num[i] << ' ';	}	cout << '\n';	return 0;}

综合归并,快排:

#include <iostream>
using namespace std;

const int N = 10e7;
int num[N];

//快速排序
void quick_sort( int q[], int l, int r )
{
	if ( l >= r ) return;
	int i = l, j = r, x = q[l + r >> 1];
	
	while ( i < j ) {
		while ( i < j && q[i] < x ) {
			++i;
		}
		
		while ( i < j && q[j] > x) {
			--j;
		}
		if ( i < j ) {
			swap(q[i], q[j]);
		}
	}
	
	quick_sort(q, l, j);
	quick_sort(q, j + 1, r);
}

//归并排序
static int tmp[N];
void merge_sort( int q[], int l, int r )
{
	if ( l >= r ) return;
	
	int mid = l + r >> 1;
	
	merge_sort(q, l, mid);
	merge_sort(q, mid + 1, r );
	
	int k = 0, i = l, j = mid + 1;
	while ( i <= mid && j <= r ) {
		if ( q[i] <= q[j] ) {
			tmp[k++] = q[i++];
		}
		else {
			tmp[k++] = q[j++];
		}
	}
	while ( i <= mid ) tmp[k++] = q[i++];
	while ( j <= r ) tmp[k++] = q[j++];
	
	for ( i = l, j = 0; i <= r; ++i, ++j ) {
		q[i] = tmp[j];
	}
}


int main()
{
    int n;
    cin >> n;
    for ( int i = 0; i < n; ++i ) {
		cin >> num[i];
	}

	//快速排序
	//quick_sort(num, 0, n-1);

	//归并排序
	merge_sort(num, 0, n-1);
	
	
	for ( int i = 0; i < n; ++i ) {
		cout << num[i] << ' ';
	}
	cout << '\n';

	return 0;
}

END

6.搜索思考题

搜索那一讲的思考题:参考代码,有更好的那自然是更好

#include <iostream>
using namespace std;
/*
表示乘号放的位置
3#2#1#5#1#2#5#4#6#9#7 #表示可以放的位置(1-10)
 1 2 3 4 5 6 7 8 9 10
location[i]表示第i个乘号放的位置
location[1]=2表示第一个称号放在2号位

这里我想到一个提高速度的办法,就是这四个乘号的位置,可以看出第1,第2...第4个乘号的位置序号
是递增的,所以第一个乘号最多只能放在7号位,你这么聪明肯定能想通的
*/
int location[5];
int loca[5];

/*
一个位置只能放一个乘号,所以需要把放了
乘号的位置标记起来,例如book[1]=true表示1号位放了乘号了,
就不能再放了
*/
bool book[11]={false};

long long answer;
char a[] = "32151254697";

//now表示现在放第几个乘号
//now_index表示从当前位置序号开始放乘号
//因为上面说了,四个乘号的位置序列是递增的
void dfs( int now , int now_index)
{
	//上面解释过了
	if ( location[1] > 7 ) {
		return ;
	}

	//放第五个乘号了,但是只有四个,所以放第五个的
	//时候,就表示放完了
	if ( now >= 5 ) {
		cout << "当前:";
		//计算结果,四个乘号分成了五个部分
		long long tempans = 1, num, prevover = 0;
		for ( int k = 1; k <= 4; ++k ) {
			num = 0;
			for ( prevover; prevover < location[k]; ++prevover ) {
				num = num * 10 + a[prevover] - '0';
			}
			cout << num << '*';
			tempans *= num;
		}

		//算第五个数
		num = 0;
		for ( prevover; prevover < 11; ++prevover ) {
			num = num * 10 + a[prevover] - '0';
		}
		cout << num << '\n';
		tempans *= num;


		if ( tempans > answer ) {
			answer = tempans;
			for ( int i = 1; i < 5; ++i ) {
				loca[i] = location[i];
			}
		}
		return ;
	}
	//枚举当前乘号放的位置
	for ( int i = now_index; i <= 10; ++i ) {
		//如果当前位置没有放乘号,那么我们就放一个乘号
		if ( !book[i] ) {
			//标记起来
			book[i] = true;
			location[now] = i;//第now个乘号放的位置存起来
			dfs(now+1, i+1);//递归下一步
			book[i] = false; //递归结束,把状态还原,回溯的重要一步
		}
	}

}

int main()
{
	int k = 1;
	dfs(1, 1);
	
	for ( int i = 0; i < 12; ++i ) {
		cout << a[i];
		if ( i+1 == loca[k] ) {
			cout << '*';
			++k;
		}
	}
	cout << '\n';
	cout << "最大值:" << answer << '\n';
	return 0;
}
//for循环简单版,但是只适用于4个乘号#include<iostream>#include<bits/stdc++.h>using namespace std;int p(char *s,int b,int r)                              {    int m = 0, i;    for(i = b; i <= r; i++)    	m=10*m+s[i]-'0';    return m;}int main(void){	char s[]="32151254697";	long long sum = 1;	for(int i = 0; i <= 6; i++)	{		for(int j = 1; j <= 7; j++)		{			for(int k = 2; k <= 8; k++)			{				for(int z = 3; z <= 9; z++)				{					if(i < j && j < k && k < z)					{						int a = p(s,0,i);						int b = p(s,i+1,j);						int c = p(s,j+2,k);						int d = p(s,k+1,z);						int e = p(s,z+1,10);						long long m = a*b*c*d*e;						if(sum < m) sum = m;					}				}			}		}	}	cout << sum << endl;	return 0;}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值