1.最优会场调度
#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.最优合并
#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.程序存储问题
#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.最优服务次序问题
#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.汽车加油问题
#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.最优分解问题
#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;
}