【完整题单10、贪心与思维】

该博客围绕贪心与思维算法给出完整题单。涵盖简单贪心、贪心交换次数、贪心 - 投资等类型题目,题目来源包括PTA、蓝桥杯、LeetCode等。详细介绍各题描述、思路与代码,如蓝桥杯付账问题需让每人出钱靠近平均数,IPO问题按启动资金排序选最大利润。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

知识框架

No.0 筑基

请先学习下知识点,阁下!
题目大部分来源于此:代码随想录:贪心

No.1 简单贪心

题目来源:PTA-L2-017 人以群分

题目描述:
在这里插入图片描述

题目思路:

题目代码:

升序排序然后直接算差值就行,如果个数奇数一定是外向的比内向的多一个。
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define N 100100
int n,m,k,g,d;
int x,y,z;
int num[N]={0};
int main() {
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>num[i];
    }
    sort(num,num+n);
    int peo=0;
    int ple=0;
    if(n%2==0){
        peo=n/2;
        ple=peo;
    }else{
        peo=n/2;
        ple=n-peo;
    }
    
    int sum1=0;
    int sum2=0;
    for(int i=0;i<peo;i++){
        sum1=sum1+num[i];
    }
    for(int i=peo;i<n;i++){
        sum2=sum2+num[i];
    }
    cout<<"Outgoing #: "<<ple<<endl;
    cout<<"Introverted #: "<<peo<<endl;
    cout<<"Diff = "<<sum2-sum1<<endl;
	return 0;
}

题目来源:PTA-L1-088 静静的推荐

题目描述:
在这里插入图片描述

题目思路:

题目代码:

//对于N要进行适应性的更改,对于字段错误
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define N 100100
int n,m,k,g,d;
int x,y,z,t;
char ch;
string str;
vector<int>v[N];
int s;
int main() {
    cin>>n>>k>>s;
    map<int,int>mp;
    set<int>sc;
    int ans = 0;
    // 算不能去的人数就行了
    for(int i=0;i<n;i++){
        cin>>x>>y;
        if(x<175){
            ans++;
        }else{
            if(y<s&&mp[x]>=k){
                ans++;
            }else{
                if(y<s){
                    mp[x]++;
                }
            }

        }
    }
    cout<<n-ans<<endl;
    

	return 0;
}




//正常计算可以去的
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define N 505000
// 下面这两个的使用;; 
#define  debug(x) cout<<#x<<" = "<<x<<endl;
#define PII pair<int,int>
int n,m,k,s,g,d;
int x,y,z;
char ch;
string str;
vector<int>v[N];
struct node{
	int tianti;
	int pta;
}stu[N];


int main()
{	
	
	
	// 得分>=175  k ci  成绩 递增 每批次不能相同成绩  pta考试+面试成绩 
	set<int>fenshu;
	cin>>n>>k>>s;
	if(k==0){
		cout<<0<<endl;
		return 0;
	}
	for(int i=1;i<=n;i++){
		cin>>stu[i].tianti>>stu[i].pta;
		fenshu.insert(stu[i].tianti);
	} 

	int res=0;
	for(auto uu:fenshu){
		if(uu<175)continue;
		int renshu=0;
		
		for(int i=1;i<=n;i++){
			if(stu[i].tianti==uu&&stu[i].pta>=s){
				res++;
				continue;
			}
			if(stu[i].tianti==uu&&stu[i].pta<s){
				renshu++;
			}
		}
		if(renshu<=k)res=res+renshu;
		else res=res+k;
		
	}
	cout<<res<<endl;
    return 0;
}

题目来源:蓝桥杯-2022省赛-修剪灌木

题目描述:
在这里插入图片描述

题目思路:

题目代码:

#include <iostream>
using namespace std;
/*
假设点i刚被修剪完为0,然后会向右/向左跑一趟,端点会被遍历1次,i与端点间的点会被遍历两次
而重新修剪i的当天早上(因为是傍晚修剪,所以当天也会被算上)达到最大高度,然后置零
也就是说:`最大长度=中间节点数*2+1(端点)+1(自生)==max(左边/右边节点数)*2`
左边端点数:i-1
右边端点数:n-i
*/
int main()
{
  int n;
  cin>>n;

  for(int i = 1;i<=n;i++) cout<<max(i-1,n-i)*2<<endl;

  return 0;
}

题目来源:蓝桥杯-2013省赛-翻硬币

题目描述:
在这里插入图片描述

题目思路:

题目代码:

//对于N要进行适应性的更改,对于字段错误
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define N 100100
long long n,m,k,g,d,t;
int x,y,z;
char ch;
string str;
vector<int>v[N];

int day[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};

int main() {
	int res=0;
	string s1,s2;
	cin>>s1>>s2;
	for(int i=0;i<s1.size()-1;i++){
		if(s1[i]==s2[i])continue;
		res++;
		s1[i]=s2[i];
		if(s1[i+1]=='o'){
			s1[i+1]='*';
		}else if(s1[i+1]=='*'){
			s1[i+1]='o';
		}
	}
	cout<<res<<endl;
	
	

	return 0;
}

题目来源:蓝桥杯-2018省赛-付账问题

题目描述:
在这里插入图片描述

题目思路:

1/其实标准差最小的意思也就是让每个人出的钱都尽量靠近平均数
2/钱不够平均数的人把钱都拿出来,钱多于平均数的人把前面的人没给出来的钱平均分一下
2/先从小到大排序,然后从钱最少的人开始遍历,如果这个人钱不够平均数,那么就让他全部交出来,同时总钱数减去他的钱数,其方差就是 (这个人的钱-average)2 ,如果扫到这个人钱已经足够了,那么他之后所有的人钱都够了,遍历结束,剩余每个人的方差为(剩余的总钱数/剩余人数-average)2;
3/最后要做的,就是在得到方差的基础上求出题目要求的标准差。

题目代码:

#include <bits/stdc++.h>
using namespace std;
 
long long a[500010];
 
int main() {
    int n;
    long long s;
    cin >> n >> s;
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    //开始贪心选择
    sort(a, a + n); //排序,从小到大
    double avg = 1.0 * s / n;
    double sum = 0.0;
    for (int i = 0; i < n; i++) {
        if (a[i] * (n - i) < s) { //把钱全拿出的人
            sum += (a[i] - avg) * (a[i] - avg);
            s -= a[i]; //更新还差多少钱
        } else { //不需要把钱全拿出的人。剩下的人中,钱最少的人都可以达到cur_avg
            double cur_avg = 1.0 * s / (n - i); //注意这里的s是还差多少钱
            sum += (cur_avg - avg) * (cur_avg - avg) * (n - i); //如果这个人有钱付,那么后面的人一定也能付,所以直接乘后面的人数(n - i)即可
            break;
        }
    }
    printf("%.4f", sqrt(sum / n));
 
    return 0;
}

题目来源:蓝桥杯-2019省赛-扫地机器人

题目描述:

在这里插入图片描述

题目思路:

题目代码:

/*
解题思路:不用遍历所有机器人的运动轨迹,只需要求出单个机器人花的最大时间
即可完成本题,利用二分查找查找最大时间
步骤:
1.利用二分查找每次分两个区域
2.定义检查函数检查是否扫完
3.在函数体内遍历每个机器人一次性扫多少个地,这个地我们用x表示,求出最小x即可
在定义一个s代表扫了多少个地,遍历完在判断s是否>=n即可,
由于每个机器人扫的地都一样,所以最后的结果一定会>=n
4.那个最小的x就是我们的最终结果
*/

#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
int n, k;
int pos[N];
bool check(int x){  //x代表一次性扫多少个地 
    /*cout << x<<endl;*/
    int s = 0;      //表示一共扫了多少地
    for(int i = 0; i < k; i++) {
        //当前扫不了 需要更大的距离才能扫
        if (pos[i]-x>s)   return false;
        if (pos[i]<= s)  s = pos[i] + x - 1;
        else              s += x;
    /*    cout << "i:" << i << "  pos[i]:" << pos[i] << "  s:" << s << endl;*/
    }
    /*cout << endl;*/
    return s>=n;
}
int main() {
    cin >> n >> k;
    for (int i = 0; i < k; i++)
    {
        cin >> pos[i];
    }
    sort(pos,pos+k);
    int left = 0, right = n;  //计算单例机器人的过程
    while (left < right) {
        int mid = (left + right) / 2;
        if (check(mid))  //如果当前距离合格 在往小的里面找合格的
            right = mid;
        else            //当前不合格  说明往大的找
            left = mid + 1;
    }
    cout << (left-1) * 2<<endl;
    return 0;


}

No.2 贪心交换次数

题目来源:蓝桥杯-第七届-交换瓶子

题目描述:
在这里插入图片描述

题目思路:

贪心的思想,但是最后好像就是 交换排序。或者是找时间复杂度最小的 排序算法。

题目代码:

#include<iostream>
using namespace std;
int main(){
	int n;
	cin>>n;
	int a[n+5];
	for(int i=0;i<n;i++)
	    cin>>a[i];
	int min;
	int num=0;
	for(int i=0;i<n;i++){
		min=i;
		for(int j=i+1;j<n;j++){//找最小的 
			if(a[min]>a[j])
			    min=j;
		}
		if(min!=i){
			num++;
			swap(a[i],a[min]);
		}
	}
	cout<<num<<endl;
	return 0;
}

题目来源 LeetCode-1007.行相等的最少多米诺旋转

题目描述:

在这里插入图片描述

题目思路:

题目代码:

class Solution {
public:
    int minDominoRotations(vector<int>& tops, vector<int>& bottoms) {
        // 判断 -1 就是这次遍历的跟前面遍历的是否有不一样的。
        // 判断翻转次数的话: min(top , bottom)
        // 因为 1<= <=6 那么就可以不使用set,直接进行for了
        

        // 不够完美,因为是根据 错误一直在调试的。
        // 总体就是找到最多的那个数字。
        int n = tops.size();
        int ans_top[10] = {0};
        int ans_bottom[10] = {0};
        ans_top[ tops[0] ]++;
        ans_bottom[ bottoms[0] ]++;

        
        for(int i = 1; i < n; i++)
        {
            if(tops[i]!=bottoms[i-1] && tops[i]!=tops[i-1] && bottoms[i]!=tops[i-1] && bottoms[i]!=bottoms[i-1])return -1;

            /// 
            ans_top[ tops[i] ]++;
            ans_bottom[ bottoms[i] ]++;
        }

        int maxx_idx = 0;
        int maxx_num = 0;
        for(int i = 1; i <= 6; i++)
        {
            if(ans_top[i] >= maxx_num){
                maxx_idx = i;
                maxx_num = ans_top[i];
            }
            if(ans_bottom[i] >= maxx_num){
                maxx_idx = i;
                maxx_num = ans_bottom[i];
            }
        }
        if((ans_bottom[maxx_idx]+ans_top[maxx_idx])<n)return -1;
        return n - maxx_num;
    }
};

No.3 贪心-投资

题目来源:LeetCode-502-IPO

题目描述:
在这里插入图片描述

题目思路:

肯定是 贪心算法了,就是按照先根据 所需的启动资金进行排序,
因为次数有限,所以不用考虑DP;即进行贪心进行;
那么每次可以根据目前所拥有的资金进行选择最大的利润。
关于为什么 是 int i = 0;在while外面?
因为 前面已经按照资金进行排序了,即当出for循环的时候,前面的都已经加入到大顶堆里面了,就是说大顶堆一直在维护着。

题目代码:

class Solution {
public:
    int findMaximizedCapital(int k, int w, vector<int>& profits, vector<int>& capital) {
        vector<pair<int,int>>pc;
        for(int i = 0; i < capital.size(); ++i){
            pc.push_back(make_pair(capital[i], profits[i]));
        }

        // 存储了pair之后进行排序
        sort(pc.begin(),pc.end());

        //每次获得利润之后,
        // 使用一个大顶堆进行维护,因为后期进行加入的话,利润也增加了
        priority_queue<int>q;
        int cnt = 0;
        int i = 0; 
        while(cnt < k){
            // 因为是按照first进行排序的,所以能加入大顶堆的都加入了。
            for(; i < capital.size()&& pc[i].first <=w; i++){
                q.push(pc[i].second);
            }
            //上面已经得到了目前资金可以得到的利润,并且大顶堆排序了
            if(q.empty())break; //项目做完了可做的;
            w = w + q.top();
            q.pop();

            cnt++;
        }
        return w;


    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值