重庆大学 数据结构与算法第三次实验课

第三次实验课

注:这是重庆大学2022级陈自郁班的第二次实验课题目内容,用于实验课后的纠错反思,不可在课上抄袭

7-1 正整数质因数分解

如果一个整数 a 除以整数 b 的商正好是整数,即 b 能够整除 a,我们就称 ba 的一个“因数”。如果因数 b 恰好是质数,我们就称其为 a 的“质因数”。

现在给你一个正整数 a,请你按照从小到大的顺序输出它所有的质因数。

输入格式:

一行,一个正整数 a(2≤a≤107)

输出格式:

一行,用空格分开的若干个正整数,即按照从小到大顺序排列的 a 的所有质因数(相同数字不重复输出)

输入样例:

30

输出样例:

2 3 5

思路:

写一个判断质数的方法,然后再从小到大判断是否是因数且满足质数,把它放到数组中,然后输出即可。

代码如下:

#include <iostream>
#include <cmath>
#include<vector>
using namespace std;

// 判断一个数是否是质数
bool is_prime(int n) {
    if (n < 2) return false;
    for (int i = 2; i <= sqrt(n); i++) {
        if (n % i == 0) return false;
    }
    return true;
}

// 输出一个数的所有质因数
vector<int> prime_factors(int n) {
    vector<int> arr;
    for (int i = 2; i <= n; i++) {
        if (n % i == 0 && is_prime(i)) {
           arr.push_back(i);
        }
    }
    return arr;
}

int main() {
    int a;
    cin >> a;
    vector<int> res;
    res=prime_factors(a);
    for(int i=0;i<res.size();i++){
        if(i==res.size()-1){
            cout<<res[i];
        }
        else{
            cout<<res[i]<<" ";
        }    
    }
    return 0;
}

7-2 二分查找

对于输入的n个整数,先进行升序排序,然后进行二分查找。

输入格式:

测试数据有多组,处理到文件尾。每组测试数据第一行输入一个整数n(1≤n≤100),第二行输入n个各不相同的待排序的整数,第三行是查询次数m(1≤m≤100),第四行输入m个待查找的整数。

输出格式:

对于每组测试,分2行输出,第一行是排序后的升序的结果,每两个数据之间留一个空格;第二行是查找的结果,若找到则输出排序后元素的位置(从1开始,每两个数据之间留一个空格),否则输出0。

输入样例:

9
4 7 2 1 8 5 9 3 6
5
10 9 8 7 -1

输出样例:

1 2 3 4 5 6 7 8 9
0 9 8 7 0

思路:

对于每组数据,先利用algorithm库中sort进行升序排序,然后输出排序数组,再进行二分查找即可

代码如下:

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

// 二分查找函数,返回元素在数组中的位置,如果不存在则返回0
int binary_search(int arr[], int n, int x) {
    int left = 0, right = n - 1;
    while (left <= right) {
        int mid = (left + right) / 2;
        if (arr[mid] == x) return mid + 1; // 位置从1开始
        else if (arr[mid] < x) left = mid + 1;
        else right = mid - 1;
    }
    return 0;
}

int main() {
    int n; // 输入的整数个数
    while (cin >> n) {
        int arr[n]; // 存储输入的整数
        for (int i = 0; i < n; i++) {
            cin >> arr[i];
        }
        sort(arr, arr + n); // 对数组进行升序排序
        for (int i = 0; i < n; i++) {
            if(i==n-1){
                cout<<arr[i];
            }
            else{
                cout << arr[i] << " "; // 输出排序后的结果
            }
            
        }
        cout << endl;
        int m; // 查询次数
        cin >> m;
        for (int i = 0; i < m; i++) {
            int x; // 待查找的整数
            cin >> x;
            if(i==m-1){
                cout << binary_search(arr, n, x);
            }
            else{
                cout << binary_search(arr, n, x) << " "; // 输出查找的结果
            }
            
        }
        cout << endl;
    }
    return 0;
}

7-3 寻找大富翁

胡润研究院的调查显示,截至2017年底,中国个人资产超过1亿元的高净值人群达15万人。假设给出N个人的个人资产值,请快速找出资产排前M位的大富翁。

输入格式:

输入首先给出两个正整数N(≤ 1 0 6 10^6 106)和M(≤10),其中N为总人数,M为需要找出的大富翁数;接下来一行给出N个人的个人资产值,以百万元为单位,为不超过长整型范围的整数。数字间以空格分隔。

输出格式:

在一行内按非递增顺序输出资产排前M位的大富翁的个人资产值。数字间以空格分隔,但结尾不得有多余空格。

输入样例:

8 3
8 12 7 3 20 9 5 18

输出样例:

20 18 12

思路:

因为数据较多,直接用sort排序可能时间较长,所以不直接排序,而是先排n中前m个数据,本题M<=10,数据较少,先填入M 个数据,用sort排序,之后对于每一个数据,与最小项相比,大于就替换最小项,再排序。

:若 N<=M, 令M=N,输入数据后直接排序即可。

代码如下:

#include <iostream>
#include <algorithm>

using namespace std;


void findTopM(long long n, long long m) {
    long long *money = new long long[m];
    
    if (n <= m) m = n;


    for (int i = 0; i < m; i++)
        cin >> money[i];
    
    sort(money, money + m);


    for (int i = m + 1; i <= n; i++) {
        long long s;
        cin >> s;

        if (s > money[0]) {
            money[0] = s;
            sort(money, money + m);
        }
    }

    for (int i = m - 1; i > 0; i--)
        cout << money[i] << ' ';

    cout << money[0];

    delete[] money;
}

int main() {
    long long n, m;
    cin >> n >> m;

    findTopM(n, m);

    return 0;
}

7-4 关于堆的判断

将一系列给定数字顺序插入一个初始为空的小顶堆H[]。随后判断一系列相关命题是否为真。命题分下列几种:

  • x is the rootx是根结点;
  • x and y are siblingsxy是兄弟结点;
  • x is the parent of yxy的父结点;
  • x is a child of yxy的一个子结点。

输入格式:

每组测试第1行包含2个正整数N(≤ 1000)和M(≤ 20),分别是插入元素的个数、以及需要判断的命题数。下一行给出区间[−10000,10000]内的N个要被插入一个初始为空的小顶堆的整数。之后M行,每行给出一个命题。题目保证命题中的结点键值都是存在的。

输出格式:

对输入的每个命题,如果其为真,则在一行中输出T,否则输出F

输入样例:

5 4
46 23 26 24 10
24 is the root
26 and 23 are siblings
46 is the parent of 23
23 is a child of 10

输出样例:

F
T
F
T

思路:

用数组构建小根堆,用哈希表来记录数组下标,然后通过字符串的知识来判断4种命题

代码如下:

#include <iostream> 
#include <string> 
#include <unordered_map> 
#include <cmath> 
using namespace std;

int H[10010],count;//数组H用来存放堆 count计数
void creatminHeap(int x)//建造小顶堆
{
    H[++count]=x;
    int t=count;
    while(t>1&&(H[t/2]>H[t]))//判断是否比父结点(数组下标/2)要小
    {
        H[t]=H[t/2];
        H[t/2]=x;//和父结点相交换
        t/=2;//记录当前下下标位置进入下一层循环
    }
    H[t]=x;
}
int main()
{
    int N,M,x,y;
   

    cin>>N>>M;
    count=0;
    unordered_map<int,int>p;//记录位置
    string s;
    for(int i=1;i<=N;i++)
    {
        cin>>x;
        creatminHeap(x);//创建小顶堆
    }
    for(int i=1;i<=N;i++)
    {
        p[H[i]]=i;//这个p数字就是来记录数组的下标 判断是根结点还是父子结点还是兄弟结点
    }
    //下面运用的就基本上是字符串的知识了
    for(int i=0;i<M;i++)
    {
        cin>>x;
        cin>>s;
        if(s[0]=='a')
        {
            cin>>y;
            getline(cin,s);
            if(p[x]/2==p[y]/2)
            {
                cout<<"T"<<endl;
            }
            else
            {
                cout<<"F"<<endl;
            }
        }
        else
        {
            cin>>s;
            cin>>s;
            if(s[0]=='r')
            {
                if(p[x]==1)
                {
                    cout<<"T"<<endl;
                }
                else
                {
                    cout<<"F"<<endl;
                }
            }
            else if(s[0]=='p')
            {
                cin>>s;
                cin>>y;
                if(p[x]==p[y]/2)cout<<"T"<<endl;
                else cout<<"F"<<endl;
            }
            else
            {
                cin>>s;
                cin>>y;
                if(p[x]/2==p[y])cout<<"T"<<endl;
                else cout<<"F"<<endl;
            }
        }
    }  
}

7-5 二分搜索

在这种经济形势下,我们都知道找工作有多难。然而,刚从大学毕业的米尔科却很幸运—他现在被克罗地亚语言学院聘为一名跑步学家。他的朋友斯拉夫科认为runeolog**y不是一门科学,因此对米尔科的相反看法感到愤怒。一个雾蒙蒙的圣诞节,米尔科的笔记本电脑坏了。由于他对电脑不在行,他把电脑交给斯拉夫科修理。斯拉夫科觉得有点淘气,于是决定把米尔科正在处理的一个文件弄乱。

该文件包含一个由R行和C列组成的矩阵。矩阵的每个元素都是一个字母。矩阵中没有两列是相等的。为了和伪科学家米尔科玩得开心,斯拉夫科决定在不违反不相等列规则的情况下,从表的顶部删除尽可能多的行。

输入格式:

第一行输入包含两个整数RC(2≤RC≤1000),分别是行数和列数。

在接下来的每一行R中,都有英文字母表中的C个小字母。这些R x C字母代表米尔科的表格(没有两列相同)。

输出格式:

输出一个整数,即可以从表顶部删除的最大行数,这样就不会有两列相等。

输入样例1:

2 6
dobarz
adatak

输出样例1:

0

输入样例2:

3 4
alfa
beta
zeta

输出样例2:

2

输入样例3:

4 6
mrvica
mrvica
marica
mateja

输出样例3:

1

思路:

首先对输入的矩阵,进行判断是否有两列相等,使用哈希表,来存储出现过的列,遍历每一列,然后存储在哈希表中,如果在集合中出现过,说明有两列相等,再通过二分搜索找到最大可删除的行数,每次二分判断是否有两列相等,如果有两列相等,行low下移,不能行high上移,最终逼近answer,(这道题如果不考虑时间限制,可以不用二分,直接遍历),注意函数返回的answer要-1,因为返回的是low

代码如下:

#include <iostream>
#include <vector>
#include <string>
#include <unordered_set>
using namespace std;

// 定义一个函数,判断一个矩阵中是否有两列相等
bool has_equal_columns(const vector<string>& matrix) {
    // 用一个无序集合来存储已经出现过的列
    unordered_set<string> columns;

    // 遍历每一列
    for (int i = 0; i < matrix[0].size(); i++) {
        // 用一个字符串来存储当前列的所有元素
        string column;
        
        // 遍历每一行
        for (int j = 0; j < matrix.size(); j++) {
            // 将当前元素加入到字符串中
            column += matrix[j][i];
        }

        // 如果当前列已经在集合中出现过,说明有两列相等,返回true
        if (!columns.insert(column).second) {
            return true;
        }
    }

    // 如果遍历完所有列都没有发现相等的列,返回false
    return false;
}

// 定义一个函数,检查在给定的行数情况下是否可以删除指定行数
bool can_delete_rows(const vector<string>& matrix, int rows_to_delete) {
    // 用一个临时矩阵来存储删除指定行数后的矩阵
    vector<string> temp(matrix.begin() + rows_to_delete, matrix.end());

    // 判断临时矩阵中是否有两列相等
    return !has_equal_columns(temp);
}

// 定义一个函数,利用二分搜索找到最大可删除行数
int binary_search_max_rows(const vector<string>& matrix) {
    int low = 0;
    int high = matrix.size();

    while (low < high) {
        int mid = low + (high - low) / 2;

        if (can_delete_rows(matrix, mid)) {
            low = mid + 1;
        } else {
            high = mid;
        }
    }

    return low;
}
int main() {
    int R, C;
    cin >> R >> C;
    // 用一个向量来存储矩阵
    vector<string> matrix;
    // 读入矩阵的每一行
    for (int i = 0; i < R; i++) {
        string row;
        cin >> row;
        matrix.push_back(row);
    }
    // 利用二分搜索找到最大可删除行数
    int answer = binary_search_max_rows(matrix);
    cout << answer-1 << endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Haru_Yuki

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值