2025年春季学期《算法分析与设计》练习4
目录
A: 快速排序
B: 随机数
C: 随机化快速排序
D: 第k小元素问题
E: 找中位数
F: 数的划分
G: 带分数
H: 最大质因数
A: 快速排序
编程实现快速排序算法,深入理解快速排序算法的基本思想。
输入
多组输入,每组第一个数字为数组长度,然后输入一个一维整型数组。
输出
输出快速排序之后的一维整型数组(升序)
样例输入 Copy
6 1 8 6 5 3 4 5 12 42 2 5 8样例输出 Copy
1 3 4 5 6 8 2 5 8 12 42
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int a[N];
void quick_sort(int a[], int l, int r)
{
if (l >= r)
return;
int x = a[(l + r + 1) / 2], i = l - 1, j = r + 1;
while (i < j)
{
do
{
i++;
} while (a[i] < x);
do
{
j--;
} while (a[j] > x);
if (i < j)
swap(a[i], a[j]);
}
quick_sort(a, l, i - 1);
quick_sort(a, i, r);
}
int main()
{
int n;
while (~scanf("%d", &n))
{
for (int i = 0; i < n; i++)
scanf("%d", &a[i]);
quick_sort(a, 0, n - 1);
for (int i = 0; i < n; i++)
printf("%d ", a[i]);
cout << endl;
}
return 0;
}
B: 随机数
有一个rand(n)的函数,它的作用是产生一个在[0,n)的随机整数。现在有另外一个函数,它的代码如下:
int random(int n, int m)
{
return rand(n)+m;
}
显而易见的是函数random(n,m)可以产生任意范围的随机数。现在问题来了,如果我想要产生范围在[a,b)内的一个随机数,那么对应的n,m分别为多少?
输入
输入的第一行为一个正整数T (T<=1000),表示一共有T组测试数据。
对于每组测试数据包含两个整数a,b (a<=b)。
输出
对于每组测试数据,输出一行包含两个整数n和m,两个整数中间有一个空格分隔。
样例输入 Copy
2 0 5 1 4样例输出 Copy
5 0 3 1
#include <iostream>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
typedef long long ll;
const int N =1e4 +5;
const int M =1e9 +7;
const int inf =0x3fffffff;
void solve(){
int n,a,b;
cin>>n;
while(n--){
cin>>a>>b;
cout<<b-a<<" "<<a<<"\n";
}
}
int main() {
ios::sync_with_stdio(0);cin.tie(0);
//int t;cin>>t;while(t--)
solve();
return 0;
}
C: 随机化快速排序
使用Java或C++等语言中内置的随机函数实现随机化快速排序,在数组中随机选择一个元素作为分区的主元(Pivot)。
输入
多组样例输入,每组由一个一维整型数组组成。
输出
随机化快速排序之后的一维整型数组(升序排列)。
样例输入 Copy
6 1 8 6 5 3 4 5 12 42 2 5 8样例输出 Copy
1 3 4 5 6 8 2 5 8 12 42
#include <iostream>
using namespace std;
const int N = 100002;
int a[N];
void quick_sort(int q[], int l, int r)
{
if (l >= r)
return;
int m = rand() % (r - l + 1) + l;
swap(q[l], q[m]);
int x = q[l];
int i = l - 1, j = r + 1;
while (i < j)
{
do
i++;
while (q[i] < x);
do
j--;
while (q[j] > x);
if (i < j)
swap(q[i], q[j]);
}
quick_sort(q, l, j);
quick_sort(q, j + 1, r);
}
int main()
{
int n;
while (~scanf("%d", &n))
{
for (int i = 0; i < n; ++i)
scanf("%d", &a[i]);
quick_sort(a, 0, n - 1);
for (int i = 0; i < n; ++i)
cout << a[i] << " ";
cout << endl;
}
return 0;
}
D: 第k小元素问题
输入一个整数数组,请求出该数组的第k小元素。要求时间复杂度为O(n)。
输入
每组输入包括两行,第一行为一个整数数组,两个数字之间用空格隔开;第二行为k值。数组中元素个数小于1000。
输出
输出第k小元素的值。
样例输入 Copy
2 5 6 1 8 7 9 2样例输出 Copy
2
#include <iostream>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
typedef long long ll;
const int N =1e3 +5;
const int M =1e9 +7;
const int inf =0x3fffffff;
int a[N];
int k;
int fun(int l,int r,int k){
if(l==r){
return a[l];
}
int i=l;
for(int j=l+1;j<=r;j++){
if(a[j]<=a[l]){
swap(a[++i],a[j]);
}
}
swap(a[i],a[l]);
int m=i-l+1;
if(k<=m){
fun(l,i,k);
}
else{
fun(i+1,r,k-m);
}
}
void solve(){
int n=0;
char c,cc;
while(cin>>a[0]){
scanf("%c",&c);
if(c!='\n'){
for(n=1;;n++){
cin>>a[n];
scanf("%c",&cc);
if(cc=='\n'){
break;
}
}
}
int k;
cin>>k;
cout<<fun(0,n,k)<<"\n";
}
}
int main() {
//ios::sync_with_stdio(0);cin.tie(0);
//int t;cin>>t;while(t--)
solve();
return 0;
}
E: 找中位数
请设计一个算法,不排序,快速计算出一个无序数列的中位数。 时间复杂度要求为O(n)。
如果有奇数个元素,中位数则是数组排序后最中间的那个数字。
如果是偶数个元素,中位数则是数组排序后最中间两个元素的平均值。输入
有多组输入,每组输入的第一行为n(1<=n<=1e5),表示该数列的元素个数。
第二行为n个整数组成的无序数列输出
每组样例输出一行,表示该无序数列的中位数。
若为偶数,请保留三位小数
若为奇数,直接输出样例输入 Copy
5 5 3 2 1 4样例输出 Copy
3
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <cstring>
#include <stack>
#include <cmath>
#include <unordered_map>
#include <set>
#include <unordered_set>
#include <map>
#include <iomanip>
#include <queue>
#define ll long long
#define MM 0x3f3f3f3f
#define pii pair<int, int>
#define pll pair<long long, long long>
using namespace std;
const int N = 1e3 + 5;
const int P = 131;
const int MOD=1e9+7;
const double PI = acos(-1.0);
//int dx[] = {0, 0, -1, 1,-1, -1, 1, 1};
//int dy[] = {1, -1, 0, 0,1, -1, 1, -1};
int n;
void fun(vector<int>& a){
nth_element(a.begin(),a.begin()+n/2,a.end());
if(n%2==1){
cout<<a[n/2]<<"\n";
}
else{
nth_element(a.begin(),a.begin()+n/2-1,a.end());
printf("%.3lf\n",0.5*(a[n/2-1]+a[n/2]));
}
}
void solve(){
while(cin>>n){
vector<int>a(n);
for(int i=0;i<n;i++){
cin>>a[i];
}
fun(a);
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
solve();
return 0;
}
F: 数的划分
使用递归编写一个程序,求一个正整数n的所有划分个数。
例如,输入3,输出3;输入4,输出5。输入
多组输入,每一组是一个正整数n。
输出
输出划分数。
样例输入 Copy
3 4样例输出 Copy
3 5
#include<iostream>
using namespace std;
int fun(int n,int m)
{
if (n == 1 || m == 1)
return 1;
if (n > m)
return fun(n - m, m) + fun(n, m - 1);
else
if (n < m)
return fun(n, n);
else
return fun(n, n-1)+1;
}
int main()
{
int n;
while (cin >> n)
cout << fun(n,n) << endl;
return 0;
}
G: 带分数
100可以表示为带分数的形式,如100 = 3+ 69258/714,还可以表示为100 = 82 + 3546/197。
注意,在上述带分数的形式中,数字1,2,3,4,5,6,7,8,9均出现一次并只能出现一次。
类似这种带分数形式,100一共有11种表示方法。输入
单组输入。
输入一个不超过10000的正整数N。输出
输出该数字用1-9九个数字不重复且不遗漏地组成带分数形式表示的全部方法的数量。
样例输入 Copy
100样例输出 Copy
11
#include <stdio.h>
#include <string.h>
int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int fun(int l, int r) {
int s = 0;
for (int i = l; i <= r; i++) {
s = s * 10 + a[i];
}
return s;
}
void swap(int *x, int *y) {
int temp = *x;
*x = *y;
*y = temp;
}
int next_permutation(int *arr, int n){
int i = n - 2;
while (i >= 0 && arr[i] >= arr[i + 1]) i--;
if (i < 0) return 0;
int j = n - 1;
while (arr[j] <= arr[i]) j--;
swap(&arr[i], &arr[j]);
int left = i + 1, right = n - 1;
while (left < right) {
swap(&arr[left], &arr[right]);
left++;
right--;
}
return 1;
}
void solve() {
int n;
scanf("%d", &n);
int s = 0;
do {
for (int i = 0; i < 6; i++) {
for (int j = i + 1; j <= 7; j++) {
int x = fun(0, i);
int y = fun(i + 1, j);
int z = fun(j + 1, 8);
if (y % z == 0 && x + y / z == n) {
s++;
}
}
}
} while (next_permutation(a, 9));
printf("%d\n", s);
}
int main() {
solve();
return 0;
}
H: 最大质因数
自然数中任何一个合数都可以表示成若干个质因数乘积的形式,如果不考虑因数的顺序,那么这个表示形式是唯一的。
把一个合数分解成几个质数相乘的形式,叫做分解质因数,这几个质数就叫做这个合数的质因数。例如,60=2×2×3×5,2024=2×2×2×11×23。所有的质因数中最大者称为最大质因数。
请编写一个程序输出一个合数的最大质因数。输入
单组输入。
输入一个不超过10^9的合数N。输出
输出该合数的最大质因数。
样例输入 Copy
2024样例输出 Copy
23
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int M =1e9 +7;
const int N =1e2 +5;
int a[N];
void solve(){
int n;
cin>>n;
int m=0;
for(int i=2;i<=sqrt(n);i++){
if(n%i==0){
a[++m]=i;
while(n%i==0){
n/=i;
}
}
}
if(n>1){
a[++m]=n;
}
cout<<a[m]<<"\n";
}
int main() {
cin.tie(0)->sync_with_stdio(false);
solve();
return 0;
}