贪心刷题复盘

最近练了一些贪心的题目,虽然思想都是局部最优的思想,但是落实到每一题上其实会有细微的差别,复盘一下题目加深印象。

P2240 【深基12.例1】部分背包问题
这一题按照性价比排序就可以了,性价比最高的排在最前面。为了避免除法带来的问题,我们比较两个点的性价比用叉乘的方式来比较

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int,int> pii;
bool cmp(pii a,pii b)
{
	return a.second*b.first>a.first*b.second;
	
}
void solve()
{
	int n,m;
	cin>>n>>m;
	vector<pii>ve(n+1);
	for(int i=0;i<n;i++)
	{
		cin>>ve[i].first>>ve[i].second;
	}
	sort(ve.begin(),ve.end(),cmp);
	
	int sum=0;
	double ans=0;
	for(int i=0;i<n;i++)
	{
		int last=0;
		last=sum;
		if(sum+ve[i].first<m){
			sum+=ve[i].first;
			ans+=ve[i].second;
		}
		else{
			ans+=(m-last)*(1.0*ve[i].second/ve[i].first);
			break;
		}
	
	}
	printf("%.2lf",ans);	
	
}

signed main()
{
	solve();
	
}

P1223 排队接水
求平均接水的最短时间,那么我们需要在人尽量多的时候先排尽量小的取水时间,从小到大排序计算总时间然后除以n就行

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int,int> pii;
bool cmp(pii a,pii b)
{
	if(a.second!=b.second) return a.second<b.second;
	else return a.first<b.first;
}
void solve()
{
	int n;
	cin>>n;
	vector<pii>ve(n+1);
	for(int i=1;i<=n;i++)
	{
		ve[i].first=i;
		cin>>ve[i].second;
	}
	sort(ve.begin()+1,ve.end(),cmp);
	int sum=0;
	for(int i=1;i<=n;i++)
	{
		sum+=(n-i)*ve[i].second;
		cout<<ve[i].first<<" ";
	
	}
	cout<<endl;
	printf("%.2lf",1.0*sum/n);
	
}

signed main()
{
	solve();
	
}

P1803 凌乱的yyy / 线段覆盖
经典的不重复的线段区间题,我们只需要把每个点按第二个值从小到大的排序,然后看看下一个点的头有没有大于等于上一个点的尾即可

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int,int> pii;
bool cmp(pii a,pii b)
{
	return a.second<b.second;
}
void solve()
{
	int n;
	cin>>n;
	vector<pii>ve(n+1);
	for(int i=1;i<=n;i++)
	{
		cin>>ve[i].first>>ve[i].second;
	}
	sort(ve.begin()+1,ve.end(),cmp);
	
	int end=ve[1].second;

	int ans=1;
	for(int i=1;i<=n;i++){
		if(ve[i].first>=end){
			end=ve[i].second;
			ans++;
		}
		
	}
	cout<<ans;
}

signed main()
{
	solve();
	
}

P1090 [NOIP2004 提高组] 合并果子 / [USACO06NOV] Fence Repair G
这一题使用一个优先队列,把每次对头的前两个拿出来,然后加起来再放进去,把队列取完就是答案了

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int,int> pii;

void solve()
{
	priority_queue<int,vector<int>,greater<int> >q;
	int n;
	cin>>n;
	while(n--)
	{
		int x;
		cin>>x;
		q.push(x);
	}	
	int ans=0;
	while(q.size()>=2)
	{
		int a=q.top();
		q.pop();
		int b=q.top();
		q.pop();
		q.push(a+b);
		ans+=a+b;
	}
	cout<<ans;
	
}

signed main()
{
	solve();
	
}

P3817 小A的糖果
每次输入的时候就检查一下和上一个加起来有没有超过题意限制,有就减掉那部分就可以了

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int,int> pii;

void solve()
{
	int n,m,sum=0;
	cin>>n>>m;
	int last=0;
	while(n--)
	{
		int x;
		cin>>x;
		if(last+x>m){
			sum+=last+x-m;
			last=m-last;
		} 
		else last=x;
		//cout<<last<<endl;
	}
	cout<<sum;
}

signed main()
{
	solve();
	
}

P1106 删数问题
遍历每一个数如果当前这个数大于后面这个数就把它给删除掉,但是要注意特判10和删除前导零,在这题我们还可以学一个技巧,就是不要前导0我们不是把它删掉,而是记录第一个不是0的下标再开始输出

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int,int> pii;

void solve()
{
	string s;
	int n;
	cin>>s;
	cin>>n;
	int l=s.size();
	while(n--)
	{
		for(int i=0;i<=l;i++)//可以删除2222这种是因为可以遍历到第l位 而第l位位'/0'其ASCII码为0  
		{
			if(s[i]>s[i+1]) {
				for(int j=i;j<=l;j++) s[j]=s[j+1];
				l--;
			break;//删完以后变成了一个新的数字,跳出循环,继续查找和删除 
			}
			
		}
		
	}
	int st=0,i=0;//st是开始输出字符串的位置,用来跳过前导0;省的删除 
	//st<l-1是为了防止10啥也不输出 
	while(s[i]=='0'&&st<l-1)
	{
		st++;
		i++; 
	}
	for(int i=st;i<l;i++) cout<<s[i];
	
}

signed main()
{
	solve();
	
}

P1478 陶陶摘苹果(升级版)
把高度小于a+b的按照消耗的力气小从小到大排序,放进优先队列即可,考虑一下特殊情况当n=0或s=0时,ans=0

点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int,int> pii;
void solve()
{
	int n,s,a,b;
	priority_queue<pii,vector<pii>,greater<pii> >q;
	cin>>n>>s;
	
	//特判 当n=0或s=0时,ans=0;
	
	cin>>a>>b;
	if(n==0) {
		cout<<"0";
		return;
	}
	while(n--)
	{
		int x,y;
		cin>>x>>y;
		if(x<=(a+b))
		{
			q.push({y,x});
		}
		
	}
	
	
	int ans=0,sum=0;
	while(1)
	{
		auto g=q.top();
		q.pop();
	//	cout<<g.first<<" "<<g.second<<endl;
		s-=g.first;
		if(s<0) break;
		ans++;
	}
	cout<<ans;
	
}


signed main()
{
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	solve();
	return 0;
}

P5019 [NOIP2018 提高组] 铺设道路
这一题的做法比较抽象,需要图形上的理解,

我们可以想象一下俄罗斯方块的消除情况,就是最底下一层可以全部消掉,当4这四层全部消掉了以后会剩下一个U字形,再删掉会剩下一个l型,很奇妙的是就是只要算出每两个相邻数的差分,当差分为正,结果加上这个值就可以,但是我还没想明白为啥

点击查看代码
#include <bits/stdc++.h>
using namespace std;
void solve()
{
	int n,last,sum=0;
	cin>>n;
	cin>>last;
	int a1=last;
	for(int i=2;i<=n;i++)
	{
		int x;
		cin>>x;
		int temp=x-last;
		if(temp>0) sum+=temp;
		last=x;
	}
	cout<<sum+a1;
	
	
	
}




int main()
{
	solve();
}

P1208 [USACO1.3] 混合牛奶 Mixing Milk
还是按照单价从小到大排序来做跟上面有一题是一样的

点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
#define int long long
char c[105][105];
int dx[]={-1,-1,0,1,1,1,0,-1},dy[]={0,1,1,1,0,-1,-1,-1};
int a[25],b[25][25];
bool cmp(pii a,pii b)
{
    if(a.first!=b.first) return a.first<b.first;
    else return a.second<b.second;
    
    
}



void solve()
{
    int n,m;
    cin>>n>>m;
    vector<pii>ve(m+1);
    for(int i=1;i<=m;i++)
    {
        cin>>ve[i].first>>ve[i].second;
    }
    sort(ve.begin()+1,ve.end(),cmp);
    
    int sum=0,last=0,ans=0;
    for(int i=1;i<=m;i++)
    {
        if(sum+ve[i].second<n){
            sum+=ve[i].second;
            ans+=ve[i].first*ve[i].second;
        }
        else {
            ans+=(n-sum)*ve[i].first;
            break;
        }
        
    }
    cout<<ans;
    
}

signed main()
{
    int t=1;
  //  cin>>t;
    while(t--)solve();
    return 0;
}

P1094 [NOIP2007 普及组] 纪念品分组
这题其实就是大小配对一下而已,还是排序一下然后取头和尾即可,用vector来存,然后开一个l 和 r ,l=1,r=m;用来取头和取尾,这个思路也是可以学习的

点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
#define int long long
char c[105][105];
int dx[]={-1,-1,0,1,1,1,0,-1},dy[]={0,1,1,1,0,-1,-1,-1};
int a[25],b[25][25];


void solve()
{
    int n,m;
    cin>>n;
    cin>>m;
    vector<int>ve(m+1);
    for(int i=1;i<=m;i++) cin>>ve[i];
    sort(ve.begin()+1,ve.end(),greater<int>());
    int l=1,r=m,ans=0;
    while(l<=r)
    {
        if(ve[l]+ve[r]<=n){
            ans++;
            l++;
            r--;
        }
        else {
            ans++;//超出范围让他自己一组
            l++;
        }
        
    }
    cout<<ans;
}

signed main()
{
    int t=1;
  //  cin>>t;
    while(t--)solve();
    return 0;
}

posted on 2024-03-22 17:09  swj2529411658  阅读(84)  评论(0)    收藏  举报

导航