贪心算法

 排序不等式

例1 OJ1319 排队接水

【分析】

1.结构体排序(sort的运用:

头文件<algorithm> -> 定义cmp -> sort(first,last,cmp))

2.总时间不包括当前接水的时间

3.接水时间越短的在越前面

【代码】

#include <bits/stdc++.h>
using namespace std;
struct s{
	int time;
	int num;
}a[1005];
int n,t,sum,ans;
bool cmp(s a1,s a2){
	return a1.time<a2.time;
}//定义结构体变量需要引用结构体名称
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i].time;
		a[i].num=i;
	}
	/*
	for(int i=1;i<n;i++){
		for(int j=1;j<=n-i;j++){			
			if(a[j].time>a[j+1].time){
				swap(a[j].time,a[j+1].time);
				swap(a[j].num,a[j+1].num);//冒泡排序,可以直接swap(a[j],a[j+1]) 
			}
		}
	}*/ 
	sort(a+1,a+n+1,cmp); //结构体排序可以用sort 
	for(int i=1;i<=n;i++){
		cout<<a[i].num<<" ";
	}
	cout<<endl;
	sum=a[1].time;
	for(int i=2;i<=n;i++){
		ans+=sum;
		sum+=a[i].time;
	}
	//cout<<ans;
	printf("%.2lf",(double)ans/n);
	return 0;
}

 例2 OJ320 均分纸牌

【分析】

 1.负数可以计算,即当纸牌数小于均值时,a[i]-ave为负数,令a[i+1]加上负数相当于a[i+1]将差值分给了a[i],仍能得到均值

2.纸牌数与均值相等时跳过

【代码】

#include <bits/stdc++.h>
using namespace std;
int a[105];
int main(){
	int n,ave,ans=0,sum=0;
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		sum+=a[i];//计算总值 
	}
	ave=sum/n;//计算均值 
	for(int i=1;i<=n;i++){
		if(a[i]==ave) continue;//纸牌数与均值相等时可直接跳过 
		else{
			a[i+1]+=a[i]-ave;//不相等时 将剩余的数分到下一个数 
			ans++;//次数增加 
		}
	}
	cout<<ans;
	return 0; 
} 

例3 OJ1321 删数问题

 【分析】

1.双层循环,第一个表明要删去s个值,每一次循环删去找到的第一个峰值,即第一个大于后面的数

2.边界问题,详见代码

3.处理前导0,但必须保留最后一位0

【代码】

#include <bits/stdc++.h>
using namespace std;
string a;//定义字符串 
int main(){
	cin>>a;
	int l,k,s;
	cin>>s;
	l=a.size();//取整数的长度 
	for(int i=1;i<=s;i++){//需要删去s个数 
		for(int j=0;j<=l-i;j++){//j从0开始遍历,而i从1开始,实际遍历到l-i位即可,不需要考虑后面的位数 
			if(a[j]>a[j+1]){
				k=j;//删去第一个峰值 
				break;
			}
		}
		//cout<<k<<" "<<a[k]<<endl;
		for(int j=k;j<=l-i;j++){
			a[j]=a[j+1];//将删去后剩余的每一位向前挪 
		}
	}
	k=0;//这里的k作下标 
	while(a[k]=='0'&& k!=l-1-s) k++;//处理前导0 
	for(int i=k;i<=l-1-s;i++){//从0开始 最后一位的下标是l-1 再减去删去的s个数 
		cout<<a[i];
	}
	return 0;
}

例4 OJ1322 导弹拦截

【分析】 

1.第一发能达到任意高度,即假设为1e9

2. 以后每一发炮弹都不能高于前一发的高度,则令拦截成功的导弹为1,并更新下一次拦截的最高高度,然后配备新的拦截系统拦截为0的导弹

【代码】

#include <bits/stdc++.h>
using namespace std;
int a[1005];
int main(){
	int k;
	int l=1;
	a[l]=1e9;//假设第一套系统的拦截高度为无限大 
	while(cin>>k){
		int flag=0;
		for(int i=1;i<=l;i++){
			if(k<=a[i]){
				a[i]=k; 
				flag=1;//已拦截的导弹标记为1 并且更新系统拦截高度 
				break;
			}
		}
		if(flag==0){
			l++;//对于没有拦截的导弹需要配备新的系统 
			a[l]=k;//设置新的拦截系统高度为k 
		}
	} 
	cout<<l;
	return 0;
} 

区间问题

例1 OJ1323 活动选择

 【分析】

1.先结束的先安排,安排的起始时间必须在空闲时间内

2.结构体排序(同上1319)

【代码】

#include <bits/stdc++.h>
using namespace std;
struct s{
	int l;
	int r;
}a[100005];//定义结构体 
bool cmp(s a1,s a2){
	return a1.r<a2.r;
}//定义cmp函数 
int main(){
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d%d",&a[i].l,&a[i].r);
	}
	sort(a+1,a+n+1,cmp);//排序 
	int kt,ans=0;
	for(int i=1;i<=n;i++){
		if(i==1){
			kt=a[i].r;
			ans++;
		}//安排第一个活动  令kt等于第一个活动的结束时间 
		else{
			if(kt<=a[i].l){//如果下一个活动的起始时间大于kt 
				kt=a[i].r; 
				ans++;//继续安排 
			}
		}
	}
	cout<<ans<<endl;
	return 0;
}

例2 OJ1324 整数区间*

【分析】

首先按右端点的大小从小到大排序(sort),并每次标记当前区间的右端点为k,下一个区间的左端点如果在k前面或与k重合,则不需要考虑;如果在k后面,则令其右端点为新的k。 

 【代码】

#include <bits/stdc++.h>
using namespace std;
struct s{
	int l,r;
}a[10005];
int cmp(s a1,s a2){
	return a1.r<a2.r;
}
int main(){
	int n;
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>a[i].l>>a[i].r;
	}
	sort(a,a+n,cmp);
	int k=-1,ans=0;
	for(int i=0;i<n;i++){
		if(a[i].l>k){//如果下一个区间的左端点大于k
			k=a[i].r;//令k等于该区间的右端点
			ans++;//计数
		}//循环比较
	}
	cout<<ans;
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值