CE16.【C++ Cont】练习题组16(堆专题)

目录

1.P3378 【模板】堆

题目

分析

代码

提交结果

2.第 k 小的数

题目

分析

方法1:建小堆(不推荐)

​编辑

方法2:建大堆(推荐)

方法2代码

提交结果

3. 除2!

题目

分析

代码

提交结果


1.P3378 【模板】堆

https://www.luogu.com.cn/problem/P3378

题目

分析

分析题目显然是建小根堆(题目没告诉是堆也要识别出来这是堆排序问题)

堆排序复习:

103.【C语言】数据结构之用堆对数组排序-CSDN博客

118.【C语言】数据结构之排序(堆排序和冒泡排序)-CSDN博客

代码

之前写过堆排序,这里直接使用STL库的优先级队列

#include <iostream>
#include <queue>  
using namespace std;
int main()
{
	priority_queue<int,vector<int>,greater<int>> q;
	int n,x,op;
	cin>>n;
	while(n--)
	{
		cin>>op;
		if (op==1)
		{
			cin>>x;
			q.push(x);
		}
		else if (op==2)
			cout<<q.top()<<endl;
		else	
			q.pop();
	}
    return 0;
}

提交结果

2.第 k 小的数

题目

https://ac.nowcoder.com/acm/problem/214362

分析

方法1:建小堆(不推荐)

录入所有数后,建小堆,由于堆顶是最小的元素,如果只从堆顶取出第k小的元素,那么需要删除堆顶元素(k-1)次,之后堆顶就是第k小,之前删除的元素保留在临时数组中,待打印第k小的元素后将删除过的元素再入堆

但这种方法有缺陷:时间复杂度太高(之前删除的元素再入堆占大量时间),不推荐使用

#include <iostream>
#include <queue>
#define endl "\n"  
using namespace std;
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);

	priority_queue<int, vector<int>, greater<int>> q;//建小根堆
	vector<int> tmp;
	int n, m, k, x, op;
	cin >> n >> m >> k;
	while (n--)
	{
		cin >> x;
		q.push(x);
	}
	while (m--)
	{
		cin >> op;
		if (op == 1)
		{
			cin >> x;
			q.push(x);
		}
		else//op==2
		{
			if (q.size() < k)
				cout << "-1" << endl;
			else
			{
				int times = k;
				times--;
				while (times--)
				{
					tmp.push_back(q.top());
					q.pop();
				}
				cout << q.top() << endl;
				while (!tmp.empty())
				{
					q.push(tmp.back());
					tmp.pop_back();
				}
			}
		}
	}
	return 0;
}

就算写出来了,牛客网上也过不了,超时

方法2:建大堆(推荐)

之前在105.【C语言】数据结构之TopK问题详细分析文章中讲过建大堆的算法

和方法1恰好相反,删除大根堆的堆顶元素(n-k)次,剩下在堆中的元素是第1小的到第k小的,堆顶为第k小的

则维护大根堆只含k个元素即可,堆顶即为第k小的元素.

方法2代码

#include <iostream>
#include <queue>
#define endl "\n"  
using namespace std;
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	
	priority_queue<int,vector<int>,less<int>> q;
	int n,m,k,x,op;
	cin>>n>>m>>k;
	while(n--)
	{
		cin>>x;
		q.push(x);
	}
	
	while(m--)
	{
		cin>>op;
		if (op==1)
		{
			cin>>x;
			q.push(x);		
		}
		while(q.size()>k)
			q.pop();
		if (op==2)
        {
            if (q.size()<k)
                cout<<"-1"<<endl;
            else
                cout<<q.top()<<endl;
        }
	}
    return 0;
}

注意while(m--)中的if判断和while(q.size()>k)的出场顺序,会影响结果的正确性

提交结果

3. 除2!

题目

https://ac.nowcoder.com/acm/problem/213140

分析

贪心算法:每次挑选出数组中最大的偶数来/2,这样可让数组中所有数之和尽可能小

最大的偶数怎么取? 答:使用大根堆! 设用sum来存储总和,如果堆顶为奇,正常将堆顶元素加到sum中,之后删除堆顶元素;如果堆顶为偶,看看k是否为正,k如果为正,先用tmp保存堆顶元素,再删除堆顶元素,将除以2后tmp的再入堆,k如果为负,正常将堆顶元素加到sum中,之后删除堆顶元素

代码

注意:本题使用int存储过不了,最大:sum=10^9*(10^5-1)=10^{14}-10^9,发现超出了int的存储范围!!

#include <iostream>
#include <queue>
#define endl "\n"  
using namespace std;
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	
	priority_queue<unsigned long long,vector<unsigned long long>,less<unsigned long long>> q;
	vector<unsigned long long> tmp;
	unsigned long long n,k,x;
	unsigned long long sum=0;
	cin>>n>>k;
	while(n--)
	{
		cin>>x;
		q.push(x);
	}
	
	while(!q.empty())
	{
		if (q.top()%2)//堆顶为奇数
		{
			sum+=q.top();
			q.pop();	
		} 
		else//堆顶为偶数
		{
			if (k>0)
			{
				int tmp=q.top();
				q.pop();
				tmp/=2;
				q.push(tmp);
				k--;
			}
			else
			{
				sum+=q.top();
				q.pop();				
			} 
		} 
	}
	cout<<sum;
    return 0;
}

提交结果

这是一个非常常见的 C++ 开发问题,尤其是在使用 IDE(如 Visual Studio、CLion、VSCode 等)时,**“转到定义”(Go to Definition)功能失效**,可能的原因有很多。我们来详细分析并提供解决方案。 --- ## ❓ 问题描述: 你在使用 IDE 时点击“转到定义”(通常是 `F12` 或右键菜单),但提示: - “无法导航到定义” - “未找到定义” - “没有可用的定义” --- ## 🧠 常见原因与解决方案: ### ✅ 1. **未正确包含头文件** 如果你在 `.cpp` 文件中定义了一个函数,但在 `.h` 文件中没有声明它,IDE 就无法找到定义。 #### 示例: ```cpp // main.cpp #include <iostream> using namespace std; void sayHello() { cout << "Hello" << endl; } int main() { sayHello(); // 此时没有函数声明,IDE 无法跳转 return 0; } ``` #### ✅ 解决方法: 在头文件中声明函数: ```cpp // sayhello.h #pragma once void sayHello(); ``` ```cpp // sayhello.cpp #include "sayhello.h" #include <iostream> using namespace std; void sayHello() { cout << "Hello" << endl; } ``` ```cpp // main.cpp #include "sayhello.h" int main() { sayHello(); // 现在可以跳转 return 0; } ``` --- ### ✅ 2. **函数未定义** 如果你只是声明了一个函数但从未实现它,IDE 也无法跳转。 #### 示例: ```cpp class MyClass { public: void doSomething(); // 只有声明 }; int main() { MyClass obj; obj.doSomething(); // 无法跳转 } ``` #### ✅ 解决方法: 定义函数: ```cpp void MyClass::doSomething() { // 实现 } ``` --- ### ✅ 3. **IDE 未正确索引代码(缓存问题)** 有时候 IDE 的索引或缓存未更新,导致跳转失败。 #### ✅ 解决方法: - **Visual Studio**: - 清理解决方案并重新生成 - 删除 `.sdf` 文件和 `.VC.db` 文件(位于项目目录) - 使用 `Ctrl + ,` 搜索“Rebuild”重建索引 - **VSCode + C/C++ 插件**: - 检查 `.vscode/c_cpp_properties.json` 是否配置正确 - 使用 `C/C++: Rebuild Intellisense` 命令 - 确保 `Include Path` 包含所有头文件路径 - **CLion**: - 重新加载 CMake 项目(Reload CMake) - 清理并重新构建项目 --- ### ✅ 4. **跨文件定义未正确链接** 如果你的函数定义在另一个 `.cpp` 文件中,但未被当前文件 `#include`,IDE 也无法跳转。 #### 示例: ```cpp // file1.cpp #include <iostream> void sayHello() { std::cout << "Hello" << std::endl; } ``` ```cpp // main.cpp void sayHello(); // 声明 int main() { sayHello(); // 虽然能编译,但 IDE 无法跳转 } ``` #### ✅ 解决方法: 将声明写入 `.h` 文件并包含它: ```cpp // sayhello.h #pragma once void sayHello(); ``` ```cpp // main.cpp #include "sayhello.h" int main() { sayHello(); // 现在可以跳转 } ``` --- ### ✅ 5. **宏定义或模板导致跳转失败** 某些复杂的宏或模板代码,IDE 可能无法解析。 #### 示例: ```cpp #define CALL(func) func() void myFunc() {} int main() { CALL(myFunc); // IDE 无法识别 } ``` #### ✅ 解决方法: - 尽量避免宏替换函数调用 - 使用模板时确保类型明确,IDE 有时无法推导 --- ## ✅ 总结:解决“无法转到定义”的步骤 | 步骤 | 操作 | |------|------| | 1 | 确保函数在头文件中声明 | | 2 | 确保函数在源文件中定义 | | 3 | 确保头文件被正确包含 | | 4 | 清理并重建项目,刷新 IDE 缓存 | | 5 | 避免使用宏替换函数调用 | | 6 | 检查 `.vscode/c_cpp_properties.json`(VSCode)等配置是否正确 | --- ##
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

zhangcoder

赠人玫瑰手有余香,感谢支持~

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

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

打赏作者

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

抵扣说明:

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

余额充值