电子学会五级-贪心算法

电子学会五级-贪心算法
1 部分背包问题
https://www.luogu.com.cn/problem/P2240

#include<bits/stdc++.h>
using namespace std;

const int MAXN=105;
int n,t;

struct mvp{
	int m;
	int v;
	float p;
};
mvp mvps[MAXN];
bool cmp(mvp mvp1,mvp mvp2){//按单价从高到底排序 
	return mvp1.p>mvp2.p;
}
float ans;

int main(){
	cin>>n>>t;
	for(int i=0;i<n;i++){
		int m,v;
		cin>>m>>v;
		mvps[i].m=m;
		mvps[i].v=v;
		mvps[i].p=v*1.0/m;
	}
	
	sort(mvps,mvps+n,cmp);//优先装单价高的 按单价从高到底排序 
	
	for(int i=0;i<n;i++){//优先装单价高的 
		if(t>=mvps[i].m){//本次可以装完 
			t-=mvps[i].m;
			ans+=mvps[i].v;
		}else{//装不完 分割装一部分 
			ans+=mvps[i].v*1.0/mvps[i].m*t;
			break;
		}
	}
	cout<<fixed<<setprecision(2)<<ans;
}

2 排队接水
https://www.luogu.com.cn/problem/P1223

#include<bits/stdc++.h>
using namespace std;

const int N=1e6+5;
int n;
struct js{
	int t;
	int idx;
}jss[N];
long long ans,curT;
bool cmp(js js1,js js2){
	return js1.t<js2.t;
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>jss[i].t;
		jss[i].idx=i;
	}
	sort(jss+1,jss+n+1,cmp);
	for(int i=1;i<=n;i++){
		cout<<jss[i].idx<<" ";
		curT+=jss[i].t;
		if(i!=n)
			ans+=curT;
	}
	printf("\n%.2f",ans*1.0/n);
}

3 合并果子
https://www.luogu.com.cn/problem/P1090

#include<bits/stdc++.h>
using namespace std;

const int MAXN=1e4+5;
int n;
int a[MAXN];
int ans;
int main(){
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>a[i];
	}
	
	sort(a,a+n);//从小到大排序 
	for(int i=1;i<n;i++){//从1开始循环 
		a[i]+=a[i-1];//从小到大合并,并且合并到大的 
		ans+=a[i];//累加两个数合并的结构到ans 
		//合并后的把a[i]放到a数组排序 
		for(int j=i+1;j<n&&a[j-1]>a[j];j++){
			swap(a[j],a[j-1]);
		}	
	}
	cout<<ans;
	return 0;
}

4 P1094 [NOIP2007 普及组] 纪念品分组
https://www.luogu.com.cn/problem/P1094

#include<bits/stdc++.h>
using namespace std;

const int N=3e4+5;
int a[N],w,n,ans;
/*
	每个组至多有两件纪念品 可以有1个或有2个 
	从大到小排序 最大的和当前最小的组合,可以就2个,不可以就当前单独1个 
*/
int main(){
	cin>>w>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	sort(a+1,a+n+1,greater<int>());//从大到小排序 
	int x=1,y=n-1;//x左边最大的 y右边最小的 
	while(x<=y){//直到x==y 时 说明已经找完  
		if(x!=y && a[x]+a[y]<=w){//x和y一起组合<w 并且x和y不是同一个  --同一个单独组成 
			x++; 
			y--;
			ans++;
		}else{
			x++;
			ans++;
		}
	}
	cout<<ans;
} 

5 P1208 [USACO1.3]混合牛奶 Mixing Milk
https://www.luogu.com.cn/problem/P1208

#include<bits/stdc++.h>
using namespace std;

const int M=5005;//最大5000个元素 
int n,m,ans;
struct milk{ 
	int p;//价格 
	int a;//数量 
}mls[M];//定义结构体数组
bool cmp(milk m1,milk m2){//按单价从低到高排序 
	return m1.p<m2.p;
}
int main(){
	cin>>n>>m;
	for(int i=0;i<m;i++){//输入 
		cin>>mls[i].p>>mls[i].a;
	}
	sort(mls,mls+m,cmp);//排序 
	for(int i=0;i<m;i++){
		if(n>=mls[i].a){//收购数量大于当前农户可提供数量 
			n-=mls[i].a;//收购当前农户 剩余数量 
			ans+=mls[i].p*mls[i].a;//累加收购需要的钱 
		}else{//收不完当前农户 只收需要收的 收完退出 
			ans+=mls[i].p*n;//累加收购需要的钱
			break;
		}
	}
	cout<<ans;
} 

6 P1106 删数问题
https://www.luogu.com.cn/problem/P1106

#include<bits/stdc++.h>
using namespace std;

const int N=255;
int k,len;
char a[N];

/*
	贪心策略 
	删除一个,在相对位置不变的情况下,应该删除相邻两个数字中前面数字较大的那个
	例如:175438
	7>5 删除7  --15438
	5>4 删除5  --1438
	4>3 删除4  --138
	8>0 删除8  --13 
*/
int main(){
	cin>>a>>k;
	len=strlen(a);
	while(k){
		//i=len-1时 i+1超边界,默认a[i+1]=0,前面没有可删除数字时 可以删除最后一个数字 
		for(int i=0;i<len;i++){ 
			if(a[i]>a[i+1]){//找出a[i]>a[i+1]的数字 删除a[i] 
				for(int j=i;j<len;j++){//i后面所有数字左移  删除a[i] 
					a[j]=a[j+1];
				}
				len--;//删除了一位,舍去最后一位 
				break;//每次只删除一位,保证删左边位权高的 
			}
		}
		k--;
	}
	int start=0;
	while(a[start]=='0' && start<len-1){//去除前导0 
		start++;
	}
	for(int i=start;i<len;i++){//输出 
		cout<<a[i];
	}
}

7 P4995 跳跳
https://www.luogu.com.cn/problem/P4995

#include<bits/stdc++.h>
using namespace std;

const int N=305;
long long ans;
int n;
int a[N];
/*
	贪心策略
	每次尽可能最高
	按从小到大排序 从最小跳到最高 再从最高跳到第2小..... 
*/
int main(){
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>a[i];
	}
	sort(a,a+n);//从小到大排序 
	bool flag=false;//区分是最小跳还是最高跳  默认false 从最小开始跳 
	int now=0,head=0,tail=n-1;//now从哪里跳  head跳完移动到下一个 tail 跳完移动到前一个 
	while(head<=tail){//最后2时 跳到其中一个 这两个指针相同 这时需要再跳到另外一个上面 
		if(!flag){//从小跳到高 
			ans+=pow(now-a[tail],2);//累加结果 
			now=a[tail];//记录本次高度 
			tail--;//指针前移 
			flag=true;//下次从高跳到低 
		}else{
			ans+=pow(now-a[head],2);//累加结果 
			now=a[head];//记录本次高度 
			head++;//指针后移 
			flag=false;//下次从低跳到高
		}
	}
	cout<<ans;	
}

8 P4447 [AHOI2018初中组]分组
https://www.luogu.com.cn/problem/P4447

#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN=1e5+40;
//f录入的数 q[i] 记录i分组下一个填写的数 siz此分组数的个数 top分组数 
int f[MAXN],n,ans=1e9,siz[MAXN],top,q[MAXN];
/*
	思路:
	排序后(从小到大排序)分组填充
	二分查找 找到第一个大于等于本次待天数的分组 填入此分组
	找不到 新建分组 
	4
	1 2 2 3
*/ 
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&f[i]);
	sort(f+1,f+n+1); q[0]=1e9+1;//从小到大排序 
	for(int i=1;i<=n;i++){
		int l=0,r=top;//所有分组二分查找 
		while(l<r){//二分查找 具体填入哪个分组 找到待填入数相同 找下一个  --分组前面长后面短 
			int mid=(l+r+1)>>1;
			if(f[i]>=q[mid]) l=mid;
			else r=mid-1;
		}
		if(q[l]!=f[i]) siz[++top]=1,q[top]=f[i]+1;//新建分组 
		else siz[l]++,q[l]++;//数字不能相同 下一个数加1 
	}
	for(int i=1;i<=top;i++) ans=min(ans,siz[i]);//找人数最少分组 
	printf("%d\n",ans);
	return 0;
}

9 P5019 [NOIP2018 提高组] 铺设道路
https://www.luogu.com.cn/problem/P5019

#include<bits/stdc++.h>
using namespace std;
int n,d[1000001];
long long ans=0;
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
		cin>>d[i];
	for(int i=2;i<=n;i++)
		if(d[i]>d[i-1])
			ans+=d[i]-d[i-1];//当前只需要铺设差,前面已经把本次免费铺设过了 
	cout<<ans+d[1];//第一个开始铺设前面的,顺便把同高度后面也铺设了 
	return 0;
}

P1080 [NOIP2012 提高组] 国王游戏
https://www.luogu.com.cn/problem/P1080
P1842 [USACO05NOV]奶牛玩杂技
https://www.luogu.com.cn/problem/P1842

5 小A的糖果
https://www.luogu.com.cn/problem/P3817
6 铺设道路
https://www.luogu.com.cn/problem/P5019
7 线段覆盖
https://www.luogu.com.cn/problem/P1803
8 陶陶摘苹果(升级版)
https://www.luogu.com.cn/problem/P1478

posted @ 2022-10-16 17:17  new-code  阅读(46)  评论(0编辑  收藏  举报