贪心专题题解

导航

页内跳转打开题目链接
APOJ_3617
BPOJ_3069
CPOJ_3253
DPOJ_2376
EPOJ_1328
FPOJ_3190
GPOJ_2393
HPOJ_1017
IPOJ_3040
JPOJ_1862
KPOJ_3262
A_Best Cow Line 回到顶部

题目大意:给个长度为n的字符串,构造一个字典序最小的字符串。构造时执行n次下述任意一种操作
1)从原字符串头部删除一个字符,加入构造字符串尾部
2)从原字符串尾部删除一个字符,加入构造字符串尾部

贪心策略:不断取S的开头和末尾中较小的字符放到T的末尾,如若相等,则比较下一对字符。

#include <iostream>
using namespace std;
//输入
int n;
char a[2005];
int main()
{
	while(cin >> n) {
		for(int i = 0; i < n; i++) {
			cin >> a[i];
		}
		string res = "";	//保存答案
		int l = 0, r = n-1; //l, r分别表示剩余字符串在原字符串a的起始与结束位置
		while(l <= r) {
			bool sign = false;	//标记,true表示左边字符小于右边字符,否则为假
			for(int i = 0; i +l <= r; i++) {
				if(a[i+l] < a[r-i]) {
					sign = true;
					break;
				}else if(a[l+i] > a[r-i]){
					break;
				}
				//如果左右相等,则比较下一对 
			} 
			if(sign) {	//左边字符小于右边字符 
				res += a[l++];		//++自增运算符,l++表示先运算,后l+1 
			}else {
				res += a[r--];	
			}
		} 
		//每80个字符,换一次行 
		for(int i = 0; i < n; i++) {
			if(i % 80 == 0 && i) {
				cout << endl;
			}
			cout << res[i];
		}
	}
	return 0;
}
B_Saruman’s Army 回到顶部

题目大意:有N头牛每分钟吃d[i]朵花,农夫把每头牛送回牛舍需要花费2*t[i]时间(来回),求送完所有牛后,最少吃了多少花朵

贪心策略:不难想到每次运的牛为破坏的花朵最多的牛,即按照单位时间吃花量排序。

#include <iostream>
#include <algorithm>
using namespace std;
//输入 
int N;
typedef struct {
	int t, d;
}Data;
Data d[100005];
bool cmp(Data d1, Data d2) {
	//按照运送时间内吃的花朵数量从大到小排序
	/*
	d1:2*d1.t*d2.d	先运送d1 
	d2:2*d2.t*d1.d  先运送d2
	return 2 * d1.t * d2.d < 2* d2.t * d1.d 
	*/ 
	return d1.t / (1.0 * d1.d) < d2.t / (1.0 * d2.d); 
}
int main() {
	while(cin >> N) {
		for(int i = 0; i < N; i++) {
			cin >> d[i].t >> d[i].d;
		} 
		sort(d, d+N, cmp);
		long long res = 0L;	//保存答案 
		int time = 0; //保存当前运送牛已花费时间 
		for(int i = 0; i < N; i++) {		//先运送吃花朵多的牛 
			res += 1L * time * d[i].d;
			time += 2 * d[i].t;
		} 
		cout << res << endl; 
	}
	return 0;
} 
C_Fence Repair 回到顶部

题目大意:给一根木板,将它锯为n块要求长度的木板,每次锯木板花费代价为模板长度,求花费代价最小值。
可将锯木板看做合并木板,便于理解

贪心策略:每次找寻长度最短与次短木板进行合并。

#include <iostream>
#include <queue>
using namespace std;
//输入
int N;
int l;

int main()
{
	while(cin >> N) {
		priority_queue<int, vector<int>, greater<int> > que; //优先队列(小根堆),队首元素为最小元素 
		for(int i = 0; i < N; i++) {
			cin >> l;
			que.push(l); 
		}
		long long res = 0L;	//保存答案,答案超过int类型表示范围 
		while(que.size() > 1) {	//保证最少有两块木板可以合并,为1时表示已合并为1块木板 
			//找寻最短与次短长度木板 
			int t1 = que.top();
			que.pop();
			int t2 = que.top();
			que.pop(); 
			//答案加上此次花费代价 
			res += (long long)t1 + t2;
			//合并后的木板加入待合并木板堆 
			que.push(t1+t2);
		}
		cout << res << endl;
	}
	return 0;
}

D_Cleaning Shifts 回到顶部

题目大意:给定N头牛和T个时间点,每头牛工作一段时间,求至少需要多少头牛课覆盖所有工作时间点(1~T)

贪心策略:每次从可选择牛中选择结束时间最迟的牛,注意题目不确保一定能完成覆盖所有工作时间

#include <iostream>
#include <algorithm>
using namespace std;
//输入
int N, T;
typedef struct {
	int start, end;
}Data;
Data d[25005];

bool cmp(Data d1, Data d2) {
	//自定义排序,按照开始时间从小到大排序,如果开始时间相同,按照结束时间从大到小排序
	if(d1.start == d2.start) {
		return d1.end > d2.end;
	} 
	return d1.start < d2.start;
} 
int main()
{
	while(cin >> N >> T) {
		for(int i = 0; i < N; i++) {
			cin >> d[i].start >> d[i].end;
		}
		sort(d, d+N, cmp);
		
		int res = 0;	//保存答案
		int r = 0; 	//当前选择的牛中工作结束时间最迟时间 
		for(int i = 0; i < N; ) {
			int temp = r; 	//保存当前可工作牛的结束最迟时间 
			while(d[i].start <= (r+1) && i < N) {//确保下一头牛的工作开始时间在当前工作牛的结束时间之前 
				temp = max(temp, d[i].end); 	//找寻结束最迟时间 
				i++;
			} 
			if(temp <= r) {		//没有找到一头牛可以完成接下来的时间段的工作 
				break;
			}else {		//已找到,更新最迟时间并让答案加1 
				r = temp;
				res++;
			}
		} 
		if(r < T) {		//未完成所有工作 
			cout << -1 << endl; 
		}else {
			cout << res << endl; 
		}
	}
	return 0;
}

E_Radar Installation 回到顶部

题目大意:地图上有n个在x轴上方的岛, 有一种半径为R的雷达,问在x轴上至少安装多少雷达可使所有岛屿均可被扫描

贪心策略:找寻每个岛屿可安装雷达区间,对区间按照结束点从小到大排序,然后开始遍历建立雷达。

#include <iostream>
#include <algorithm>
#include <cmath> 
using namespace std;
const int INF = 0x3f3f3f3f;
//输入 
int n, r;
int x, y;

typedef struct {
	double start, end; //覆盖当前岛屿的雷达起止坐标 
}Data;
Data d[1005];

bool cmp(Data d1, Data d2) {
	//自定义排序,按照时间从小到大排序 
	if(d1.end == d2.end){
		return d1.start < d2.start;
	} 
	return d1.end < d2.end;
}
int main() {
	int ans = 1; 
	while(cin >> n >> r) { 
		if(n == 0  && r == 0) {
			break;
		}
		bool sign = true;	//标记,如果为false则表示有岛屿雷达不可能覆盖到 
		for(int i = 0; i < n; i++) {
			cin >> x >> y; 
			if(y > r) {		//雷达不可能覆盖该岛屿 
				sign = false;
			}else {
				//求该岛屿起止坐标(雷达都在海岸线上(即x轴上),所以只需横坐标) 
				d[i].start = (double)x - sqrt((double)(r * r - y * y));  
				d[i].end = (double)x + sqrt((double)(r * r - y * y));
			}
		} 
		cout << "Case " << ans++ << ": "; 
		if(!sign) {	//无解决方案 
			cout << -1 << endl; 
			continue;
		}
		
		sort(d, d+n, cmp);
	
		int res = 0;		//保存答案
		double right = -1.0 * INF; 		 //当前雷达覆盖最右位置 
		for(int i = 0; i < n; i++) {
			if(d[i].start > right) {		//需要添加新的雷达覆盖该岛屿 
				res++;
				right = d[i].end;		//更新雷达覆盖位置 
			}
		} 
		cout << res << endl; 
	}
	return 0;
} 
F_Stall Reservations 回到顶部

题目大意:有N头奶牛需要挤奶,每头奶牛在挤奶时间段中独占一个栅栏位,问最少需要多少栅栏位供所有奶牛挤奶。输出栅栏个数且输出每头奶牛用的栅栏位编号,编号从1开始。

贪心策略:按开始时间顺序遍历所有奶牛并放入栅栏内, 维护栅栏队列,即每次判断是否有奶牛结束挤奶工作让出栅栏位,如果有则可不用申请栅栏,换头奶牛完成任务,否则再申请一个栅栏用于当前奶牛工作。

#include <iostream>
#include <algorithm>
#include <queue> 
using namespace std;
//输入 
int N;
typedef struct Data {
	int start, end;	//起止时间
	int id;	//牛的编号
	friend bool operator < (Data d1, Data d2) {
		//重载'<'运算符,使得优先队列队首为已经挤奶的奶牛中结束时间最早的奶牛 
		if(d1.end == d2.end) {
			return d1.start > d2.start;
		}
		return d1.end > d2.end;
	} 
}Data; 

Data d[50005];
int res[50005];		//保存答案 
bool cmp(Data d1, Data d2) {	 
	//自定义排序方式,使得按照开始时间从小到大排序
	if(d1.start == d2.start) {
		return d1.end < d2.end;
	}	 
	return d1.start < d2.start;
}
int main() {
	while(cin >> N) {
		for(int i = 0; i < N; i++) {
			cin >> d[i].start >> d[i].end;
			d[i].id = i;
		} 
		sort(d, d+N, cmp);
		

		priority_queue<Data> que;		//维护栅栏中正在挤奶的牛 
		que.push(d[0]);		//压入第一头 
		int ans = 1;		//当前栅栏数 
		res[d[0].id] = ans;
		for(int i = 1; i < N; i++) {
			Data temp = que.top();
			if(temp.end < d[i].start) {	//已有奶牛挤奶结束,当前奶牛可放入该栅栏中 
				que.pop();		//挤奶结束奶牛退出栅栏 
				res[d[i].id] =  res[temp.id];	//和推出的奶牛在同一编号栅栏中 
			} else {	//当前最早结束挤奶的奶牛还没有结束,即所有奶牛都没有结束挤奶,需要添加栅栏位 
				ans++;
				res[d[i].id] = ans; 
			} 
			que.push(d[i]);		//压入当前奶牛 
		} 
		cout << ans << endl;
		for(int i = 0; i < N; i++) {
			cout << res[i] << endl; 
		} 
	}
	return 0;
} 
G_Yogurt factory 回到顶部

题目大意:奶酪工厂在接下来N星期的单位奶酪成本价为C,所需订单奶酪为Y,奶酪工厂也可花费每周每单位S单价存储本周生产奶酪。 所以每周订单奶酪可由以前生产。问奶酪工厂这N周完成订单最小代价

贪心策略:每周订单寻找最小花费代价,即本周生产或者由以前生产。

#include <iostream>
#include <algorithm>
using namespace std;
int N, S;
typedef struct {
	int c, y;
}Data;
Data d[10005];
int main() {
	while(cin >> N >> S) {
		for(int i = 0; i < N; i++) {
			cin >> d[i].c >> d[i].y;
		}  
		long long res = 0;	//保存答案,题目提示int范围无法满足题目要求 
		res += 1L * d[0].c * d[0].y;	//第一天只能当天生产
		int min_pre = d[0].c;  	//保存以前每单位最低成本  
		for(int i = 1; i < N; i++) {
			min_pre = min(min_pre+S, d[i].c);	//找寻单位最小花费 
			res += 1L * min_pre * d[i].y;		//加上本周代价 
		} 
		cout << res << endl;
	}
	return 0;
} 
H_Packets 回到顶部

题目大意:输入6个数字表示6中底面积不同的各箱子个数,将所有箱子都打包到地底面积为66的箱子中(包括题目给出的66样式的箱子),最少需要多少箱子。所有箱子高度相同

贪心策略:此题感觉就写这比较麻烦,就尽可能多的装满每个箱子即可。

#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
//输入
int a[6]; 
int main() {
	while(true) {
		int sum = 0;
		for(int i = 0; i < 6; i++) {
			cin >> a[i]; 
			sum += a[i];
		} 
		if(sum == 0) {
			break;
		}
		
		int res = 0;		//保存答案
		//从大到小开始放箱子
		//放6*6箱子 
		res += a[5];		//6*6箱子每个单独占用一个箱子

		//放5*5的箱子:每个箱子可放一个5*5的箱子,再放入11个1*1的箱子
		res += a[4];
		a[0] -= min(a[0], a[4] * 11);  //放入1*1的箱子

		//放4*4的箱子:每个箱子可以放入一个4*4的箱子,还有5个2*2的空间
		res += a[3]; 
		int temp1 = a[3] * 5;		//计算2*2空间个数 
		if(temp1 > a[1]) {		//放2*2的箱子后有剩余空间 
			a[0] -= min(a[0], 4*(temp1-a[1])); 
		}
		a[1] -= min(a[1], temp1);		//放入2*2的箱子
	
		//放3*3的箱子:每个箱子可以放4个3*3的盒子,每个3*3的盒子可以放1个2*2的盒子+5个1*1
		res += ceil(a[2] / 4.0);
		if(a[2] % 4 != 0) {	//有剩余n个3*3的空间 
			temp1 = 4 - (a[2] % 4);	//计算3*3空间个数 
			if(temp1 == 1) {		//1个 
				a[1] -= min(a[1], temp1);		//放入2*2的箱子
				if(a[1] == 0) {			//无2*2的箱子,放入1*1的箱子 
					a[0] -= min(a[0], temp1 * 9); 
				} else {		//放入1个2*2的箱子后,放入1*1的箱子 
					a[0] -= min(a[0], 5);	
				} 
			}else if(temp1 == 2) {	//2个3*3空间 
				int temp = min(a[1], 3);		//2*2箱子最多放3个 
				a[1] -= temp;	//放入2*2的箱子 
				a[0] -= min(a[0], (3-temp) * 4 + 6); 
			}else if(temp1 == 3) { //3个3*3空间 
				int temp = min(a[1], 5);	//2*2的箱子最多放5个
				a[1] -= temp;	//放入2*2的箱子 
				a[0] -= min(a[0], (5-temp) * 4 + 7);
			}
		}

		//2*2的箱子:每个6*6空间可放9个2*2的箱子
		temp1 = ceil(a[1] / 9.0);	 
		res += temp1;	//放入2*2的箱子
		if(a[1] % 9 != 0) {	//有剩余空间 
			temp1 = a[1] % 9; //计算占用空间
			a[0] -= min(a[0], 36 - temp1 * 4); 	//剩余空间放入1*1箱子 
		} 

		//放入1*1的箱子
		temp1 = ceil(a[0] / 36.0);
		res += temp1;
		
		cout << res << endl; 
	}
	return 0;
} 
I_Allowance 回到顶部

题目大意:约翰有一套N个不同面值的钱币,面值为v的钱币有b张,约翰每周至少给Bessie C元钱币,问最多可以支付多少周

贪心策略:两种情况,1)当一张纸币面值足以支付时,直接支付。 2)当一张不足以支付时,用多张钱币凑足不少于C的钱币(此过程贪心,即每次凑币方案结果极可能接近C),
凑钱币的过程中应先尽可能的凑够C(可以小于等C,等不能超过C),然后再去凑满C(尽可能小的超过C,可以等于),即从小到大遍历
可能有多种凑币方式,即重复凑币的过程,直至完全找不到方案。

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int INF = 0x3f3f3f3f;
int N, C;
typedef struct {
	int v, b;
}Data;
Data d[25];

bool cmp(Data d1, Data d2) {
	//按面值从大到小排序 
	return d1.v > d2.v;
}
int main() {
	while(cin >> N >> C) {
		for(int i = 0; i < N; i++) {
			cin >> d[i].v >> d[i].b; 
		} 
		sort(d, d+N, cmp);
		
		int res = 0;		//保存答案
		int i = 0;
		for(; i < N && d[i].v >= C; i++) { //面值大于等于零用钱的直接发放 
			res += d[i].b; 
			d[i].b = 0;
		}
		//面值不够零用钱的,多张钱币凑
		while(true) {
			vector<int> ans(25, 0);	//ans[i]表示凑够一次零用钱第i张钱币被用几张
			int temp = C; //表示当前还需多少钱凑够C 
			for(int j = i; j < N; j++) {	  	//从大到小遍历,尽可能使钱币凑近C 
				while(ans[j] < d[j].b && temp-d[j].v >= 0) { //满足使用纸币个数不超过该纸币拥有个数,且尽可能靠近C,但不能超过C 
					ans[j]++;
					temp -= d[j].v;
				}  
			} 
			for(int j = N-1; j >= i; j--) {		//从小到大遍历,凑足C,且付出当前最小代价,即超出C最小 
				while(ans[j] < d[j].b && temp > 0) { //满足使用纸币个数不超过该纸币拥有个数,且超出C尽可能小 
					ans[j]++;	
					temp -= d[j].v;
				}
			}
			if(temp > 0) {	//没有凑够C,无满足条件,退出 
				break; 
			} 
			//寻找当前钱币个数使用此种方法最多可凑多少套 
			int min_ans = INF;
			for(int j = i; j < N; j++){
				if(ans[j] != 0) {
					min_ans = min(d[j].b/ans[j], min_ans);
				}
			}
			res += min_ans;
			//更新剩余钱币剩余个数
			for(int j = i; j < N; j++) {
				d[j].b -= ans[j] * min_ans;
			} 
		} 
		cout << res << endl; 
	} 
	return 0;
} 
J_ Stripies 回到顶部

此题提交G++与C++区分,该代码为C++代码
题目大意:有种生物可以两两合并,合并后的重量为 2sqrt(m1*m2),给N个生物的体重,求合并成1个生物后的体重

贪心策略:数字越大,开平方减去部分越多,即每次让最重与次重合并

#include <iostream>
#include <cstdio> 
#include <queue>
#include <cmath> 
using namespace std;
int N;
double a;
int main() {
	while(cin >> N) {
		priority_queue<double> que;	//大根堆,队首位最大值 
		for(int i = 0; i < N; i++) {
			cin >> a;
			que.push(a); 
		}
		while(que.size() > 1) {
			//每次去最重合次重动物,组合 
			double t1 = que.top();
			que.pop();
			double t2 = que.top();
			que.pop();
			double temp = 2 * sqrt(t1 * t2);		//合并 
			que.push(temp);
		} 
		double res = que.top();
		printf("%.3lf\n", res);
	}
	return 0;
} 
K_Protecting the Flowers 回到顶部

题目大意:有N头牛每分钟吃d[i]朵花,农夫把每头牛送回牛舍需要花费2*t[i]时间(来回),求送完所有牛后,最少吃类多少花朵

贪心策略:不难想到每次运的牛为破坏的花朵最多的牛,即按照单位时间吃花量排序。

#include <iostream>
#include <algorithm>
using namespace std;
//输入 
int N;
typedef struct {
	int t, d;
}Data;
Data d[100005];
bool cmp(Data d1, Data d2) {
	//按照运送时间内吃的花朵数量从大到小排序
	/*
	d1:2*d1.t*d2.d	先运送d1 
	d2:2*d2.t*d1.d  先运送d2
	return 2 * d1.t * d2.d < 2* d2.t * d1.d 
	*/ 
	return d1.t / (1.0 * d1.d) < d2.t / (1.0 * d2.d); 
}
int main() {
	while(cin >> N) {
		for(int i = 0; i < N; i++) {
			cin >> d[i].t >> d[i].d;
		} 
		sort(d, d+N, cmp);

		long long res = 0L;	//保存答案 
		int time = 0; //保存当前运送牛已花费时间 
		for(int i = 0; i < N; i++) {		//先运送吃花朵多的牛 
			res += 1L * time * d[i].d;
			time += 2 * d[i].t;
		} 
		cout << res << endl; 
	}
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值