HBU算法设计与分析 贪心算法

1.最优会场调度

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
typedef pair<int,int> PII;
PII p[N];
priority_queue<int,vector<int>,greater<int>> q;  //最小堆 存储最早结束的会场的结束时间 
int n;
//其实这个题可以理解为同一个会场在同一个时间内只能进行一个活动 
//现在问所有活动都要正常进行 最少需要几个会场 
int main(){
	cin>>n;
	for(int i=0;i<n;i++) cin>>p[i].first>>p[i].second;
	sort(p,p+n);//默认按照所有活动的开始时间排序 
	q.push(p[0].second); //第一个活动一定不用开新会场 
    //贪心思想:每次直接与最早结束的会场的结束时间相比 只要能用 就用该会场 不能用就代表其他的也会场肯定不能用 直接开一个新会场
	for(int i=1;i<n;i++){
		if(!q.empty()&&p[i].first>=q.top()) q.pop();  
		// 如果最早结束的会场可以容纳当前活动,则复用该会场
		q.push(p[i].second);
	}
	cout<<q.size()<<endl;
	return 0;
} 

2.最优合并

cpp 复制代码
#include <bits/stdc++.h>
using namespace std; 
priority_queue<int> pmax; //大根堆
priority_queue<int,vector<int>,greater<int> > pmin; //小根堆
int n,x;

int getmin(){
	int sum=0;
	while(pmin.size()>1){
		int a=pmin.top();pmin.pop(); 
		int b=pmin.top();pmin.pop();
        //贪心思想:每次取出堆中的两个值 根据堆的性质 取出的值必定为最小的两个值
		sum+=a+b;
		pmin.push(a+b); //计算结果再加入堆中
	}
	return sum;
}
int getmax(){
	int sum=0; //与小根堆计算思想相同
	while(pmax.size()>1){
		int a=pmax.top();pmax.pop();
		int b=pmax.top();pmax.pop();
		sum+=a+b;
		pmax.push(a+b);
	}
	return sum;
}

int main(){
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>x;
		pmin.push(x); //将每个值都在两个堆中各入堆一次
		pmax.push(x);
	}
	cout<<getmax()<<" "<<getmin()<<endl;
	return 0;
}

3.程序存储问题

cpp 复制代码
#include <iostream>
#include <algorithm>
using namespace std;
int n,m,sum,cnt,a[100005];
int main() {
    cin>>n>>m;
    for(int i=0;i<n;i++) cin>>a[i];
    sort(a,a+n);
    //贪心思想:只要还没达到临界值 就一直加 达到就直接break掉 程序结束
    for(int i=0;i<n;i++){
    	sum+=a[i];
    	if(sum<=m) cnt++; 
    	else break;
	}
	cout<<cnt<<endl;
    return 0;
}

4.最优服务次序问题

cpp 复制代码
#include <iostream>
#include <algorithm>
using namespace std;
const int N=1e5+5;
typedef long long LL;
int n,a[N];
int main(){
	cin>>n;
	for(int i=0;i<n;i++) cin>>a[i];
	sort(a,a+n);
    //贪心思想:后面的每一个人都要把他排在他前面的所有时间各等一遍 所以前面的人越短越好 所以直接让每个位置都取 能取到的最短 即直接升序排序
	LL time=0;
	for(int i=0;i<n;i++) time+=(n-i)*(LL)a[i]; //每一个时间被等待了n-i次
	double res=time/(double)n;
	printf("%.2lf",res);
	return 0;
}

5.汽车加油问题

cpp 复制代码
#include <iostream>
using namespace std;
const int N=1e5+5;
int n,k,sum,cnt,a[N];
int main(){
	cin>>n>>k;
	for(int i=0;i<=k;i++) {
		cin>>a[i];
		if(a[i]>=n){
			cout<<"No Solution";
			return 0;
		}
	}
	for(int i=0;i<=k;i++){
		if(sum+a[i]>n){ //贪心思想:尽可能多走 直到无法走 就选择加油
			cnt++;
			sum=0;
	    }
		sum+=a[i];
	}
	cout<<cnt;
	return 0;
}

6.最优分解问题

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int n,index,a[100001];
//解题关键点为要是自然数乘积最大 应使其2 3 5 7 小数尽可能多
//eg 5=2+3 但x*5一定小于x*2*3   即若a+b=定值,a-b的绝对值越小,ab值越大 
//所以只需要尽可能找能除尽的小数即可 

vector<int> res={1}; //高精度模板 
vector<int> mul(vector<int> A,int b){
	vector<int> C;
	int t=0;
	for(int i=0;i<A.size()||t;i++){
		if(i<A.size()) t+=A[i]*b;
		C.push_back(t%10);
		t/=10;
	}
	while(C.size()>1&&C.back()==0) C.pop_back();
	return C;
}

int main(){
	cin>>n;

	//初始化第一次分解 
	 //只要n>3 结果中就一定会有2 
	a[index++]=2;
	n-=2; 
	//利用循环分解掉n
	int i=3;
	while(n>a[index-1]){
		a[index]=i++;
		n-=a[index];
		index++;
	} 
	//贪心思想:尽量取小值 在不重复的情况下 尽量把多出来的值 分配给尽可能多的数
	//将剩下的部分x 分为x个一(因为平均分配给每一个比直接分配个某个数+x 要大 上面已证明过) 
	//从大的数开始加 因为从小数开始会重复 
	for (int i=index-1;n>0;i--) {
        a[i]++;
        if(i==0) i=index; // 循环分配
        n--;
    }
	//后几组测试数据位数过大 所以使用高精度转换
	for(int i=0;i<index;i++)  res=mul(res,a[i]); 
	for(int i=res.size()-1;i>=0;i--) cout<<res[i];
	return 0;
} 
相关推荐
疯狂吧小飞牛41 分钟前
无锁编程–C语言
c语言·数据结构·c++·算法
梦深时有鹿1 小时前
C#基础上机练习题
数据结构·算法·c#
cccccc语言我来了1 小时前
详解 【AVL树】
数据结构·c++
wqyc++1 小时前
C++ 中的 Lambda 表达式
开发语言·c++
2303_Alpha1 小时前
数据结构——哈夫曼编码
c语言·数据结构·笔记·算法·图论
skaiuijing1 小时前
Sparrow系列拓展篇:对信号量应用问题的深入讨论
c语言·开发语言·算法·中间件·操作系统
灰末2 小时前
[第15次CCFCSP]数据中心
数据结构·c++·算法·图论·kruskal
Qhumaing2 小时前
C/C++学习-引用
c语言·c++·学习
qystca2 小时前
洛谷 P1049 [NOIP2001 普及组] 装箱问题 C语言 记忆化搜索->‘倒序‘dp->‘正序‘dp
c语言·数据结构·算法
thesky1234562 小时前
活着就好20241126
学习·算法