第三次实验课
注:这是重庆大学2022级陈自郁班的第二次实验课题目内容,用于实验课后的纠错反思,不可在课上抄袭
7-1 正整数质因数分解
如果一个整数 a 除以整数 b 的商正好是整数,即 b 能够整除 a,我们就称 b 是 a 的一个“因数”。如果因数 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 root
:x
是根结点;x and y are siblings
:x
和y
是兄弟结点;x is the parent of y
:x
是y
的父结点;x is a child of y
:x
是y
的一个子结点。
输入格式:
每组测试第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列组成的矩阵。矩阵的每个元素都是一个字母。矩阵中没有两列是相等的。为了和伪科学家米尔科玩得开心,斯拉夫科决定在不违反不相等列规则的情况下,从表的顶部删除尽可能多的行。
输入格式:
第一行输入包含两个整数R和C(2≤R、C≤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;
}