《算法笔记》学习日记——4.4 贪心

4.4 贪心

Codeup Contest ID:100000584

问题 A: 看电视

题目描述
暑假到了,小明终于可以开心的看电视了。但是小明喜欢的节目太多了,他希望尽量多的看到完整的节目。
现在他把他喜欢的电视节目的转播时间表给你,你能帮他合理安排吗?
输入
输入包含多组测试数据。每组输入的第一行是一个整数n(n<=100),表示小明喜欢的节目的总数。
接下来n行,每行输入两个整数si和ei(1<=i<=n),表示第i个节目的开始和结束时间,为了简化问题,每个时间都用一个正整数表示。
当n=0时,输入结束。
输出
对于每组输入,输出能完整看到的电视节目的个数。
样例输入

12
1 3
3 4
0 7
3 8
15 19
15 20
10 15
8 18
6 12
5 10
4 14
2 9
0

样例输出

5

思路
这题就是很典型的一个区间贪心问题,能看到完整电视节目的个数,其实就是让我们在这些区间里,尽可能多地寻找两两没有交集的区间个数。我在这里采用了总是选择左端点最大的区间这一策略。
代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<algorithm>
using namespace std;
struct program{
	int s,e;
}p[100];
bool cmp(program a, program b){
	if(a.s!=b.s) return a.s>b.s;//左端点从大到小排序
	else return a.e<b.e;//如果左端点相等,则右端点从小到大排序 
}
int main(){
	int n;
	while(scanf("%d", &n) != EOF){
		if(n==0) break;
		for(int i=0;i<n;i++) scanf("%d%d", &p[i].s, &p[i].e);
		sort(p,p+n,cmp);
		int ans, lastX;
		ans = 1;
		lastX = p[0].s;
		for(int i=1;i<n;i++){
			if(p[i].e<=lastX){//如果下一个区间的右端点小于等于上一个区间的左端点
				lastX = p[i].s;//把下一个区间的左端点赋给lastX,更新
				ans++;//方案数加1
			}
		}
		printf("%d\n", ans);
	}
	return 0;
} 

问题 B: 出租车费

题目描述
某市出租车计价规则如下:起步4公里10元,即使你的行程没超过4公里;接下来的4公里,每公里2元;之后每公里2.4元。行程的最后一段即使不到1公里,也当作1公里计费。
一个乘客可以根据行程公里数合理安排坐车方式来使自己的打车费最小。
例如,整个行程为16公里,乘客应该将行程分成长度相同的两部分,每部分花费18元,总共花费36元。如果坐出租车一次走完全程要花费37.2元。
现在给你整个行程的公里数,请你计算坐出租车的最小花费。
输入
输入包含多组测试数据。每组输入一个正整数n(n<10000000),表示整个行程的公里数。
当n=0时,输入结束。
输出
对于每组输入,输出最小花费。如果需要的话,保留一位小数。
样例输入

3
9
16
0

样例输出

10
20.4
36

思路
这题主要是需要数学分析一下,当分析出来结论之后也是好写的。
这里设公里数为x,那么有:

首先,x≤4的话,肯定是10元,这个不用多说;
其次,如果4<x≤8的话,肯定是选择直接一次完成,对应的函数2x+2,如果x=8的话是18;
最后,如果x>8的话,对应的函数是2.4x-1.2;

但是这里要分类讨论一下,经过计算可以得到,x=13时,分8、5两段走和13公里一起走完所花费的钱是一样的(18+2*5+2=30和2.4*13-1.2=30),而x<13时,一段直接走完比较便宜,x>13时,分开走便宜,那么就可以得出结论了:

  • 当公里数满足1≤x%8(x除8的余数)≤5时,(8+x%8)这么多公里一段直接走完便宜,再加上前面有多少个8就行了(比如20%8=4,那么最便宜的走法是8+12,也就是18+2.4*12-1.2=45.6元);
  • 当公里数满足x%8==0或6或7,那么每段分开走比较便宜(比如22%8=6,那么最便宜的走法是8+8+6,也就是18×2+2*6+2=50元)

代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<algorithm>
using namespace std;
int main(){
	double n;
	while(scanf("%lf", &n) != EOF){
		if(n==0) break;
		if(n<=4) printf("10\n");
		else if(fmod(n,8)>=1&&fmod(n,8)<=5){
			double cost;
			cost = 2.4*(8+fmod(n,8))-1.2 + floor(n/8-1)*18;
			if(cost-(int)cost==0) printf("%.0f\n", cost);//如果一个数减去它的整数部分是0,说明没有小数部分 
			else printf("%.1f\n", cost);//否则保留一位小数点 
		}
		else if(fmod(n,8)>=6&&fmod(n,8)<=7){
			double cost;
			cost = 2*fmod(n,8)+2 + floor(n/8)*18;
			if(cost-(int)cost==0) printf("%.0f\n", cost);
			else printf("%.1f\n", cost);
		}
		else{
			double cost;
			cost = floor(n/8)*18;
			if(cost-(int)cost==0) printf("%.0f\n", cost);
			else printf("%.1f\n", cost);
		}
	}
	return 0;
} 

问题 C: To Fill or Not to Fill

题目描述
With highways available, driving a car from Hangzhou to any other city is easy. But since the tank capacity of a car is limited, we have to find gas stations on the way from time to time. Different gas station may give different price. You are asked to carefully design the cheapest route to go.
输入
Each input file contains one test case. For each case, the first line contains 4 positive numbers: Cmax (<= 100), the maximum capacity of the tank; D (<=30000), the distance between Hangzhou and the destination city; Davg (<=20), the average distance per unit gas that the car can run; and N (<= 500), the total number of gas stations. Then N lines follow, each contains a pair of non-negative numbers: Pi, the unit gas price, and Di (<=D), the distance between this station and Hangzhou, for i=1,…N. All the numbers in a line are separated by a space.
输出
For each test case, print the cheapest price in a line, accurate up to 2 decimal places. It is assumed that the tank is empty at the beginning. If it is impossible to reach the destination, print “The maximum travel distance = X” where X is the maximum possible distance the car can run, accurate up to 2 decimal places.
样例输入

59 525 19 2
3.00 314
3.00 0

样例输出

82.89

提示
该题目所要解决的问题是:给定若干加油站信息,问能否驾驶汽车行驶一定的距离。如果能够行驶完全程,则计算最小花费。若不能行驶完全程,则最远能够行驶多长距离。
拿到这一题,首先判断汽车是否能够行驶到终点。什么情况下汽车无法行驶到终点呢?两种情况:起点根本就没有加油站,汽车无法启动;或者中途两个加油站之间的距离大于加满油后汽车能够行驶的最大距离。前者汽车行驶的最大距离为0.00,而后者最大距离为当前加油站的距离加上在这个加油站加满油后能够行驶的最大距离。在这里,需要将加油站按到杭州的距离从小到大排序。
接下来在能够行驶到终点的情况下计算最小花费。我们首先从路程来考虑,如果在路上,我们能够使用最便宜的汽油,当然就在那个加油站加油了。所以从起点开始遍历每个加油站。假设遍历到了第i个加油站,我们现在来判断在加油站i应该加多少油。设当前汽车离杭州的距离为curLen,当前加油站离杭州的距离为nodes[i].dis,加满油以后汽车能够行驶的最大距离为(dis=cmax*len)。这样就有node[i].dis <= curLen <= nodes[i].dis+dis,否则的话第i个加油站的油是不起作用的。于是在第i个加油站的作用范围内寻找有没有更为便宜的加油站,如果有,则下次使用这个加油站的油(j),这次汽车应该行驶到这个加油站,即touch=nodes[j].dis。如果没有找到更为便宜的加油站则可以在第i个加油站加满油,即touch=nodes[i].dis+dis。然后判断下次应该行驶到的距离与当前距离的关系,如果下次应当行驶到的距离大于当前距离,则汽车行驶,否则不动(也就是说上个加油站的油更便宜,后一个加油站也便宜,根本就不需要在当前加油站加油)。
思路
主要思路还是利用贪心达到每步花费最少,最后就能得到整条路的最少花费了,但是这里的贪心要分很多种情况,看图吧~
(我的代码codeup和PAT都能AC,但是牛客网有一个样例过不了,就是第一行输入7 1542 15 500的那个,不知道是哪儿没考虑到,所以这个代码只能当做参考哈,并不是完整的解题答案
2020.3.23补充:原因找到了,因为牛客网给的样例里包含油价为0的情况而我的代码一开始寻找最小油价以及次小油价中,if的判断条件是:

nodes[k].price<min&&nodes[k].price>0

而如果油价是0的话就会自动跳过这句话,也就是说,原来我写的方案是找最小的正整数,现在要找最小非负数的话只要加上等号就行了:

nodes[k].price<min&&nodes[k].price>=0

在这里插入图片描述
为了方便对比,我把PAT的两个样例也放在这里:
Sample Input 1:

50 1300 12 8
6.00 1250
7.00 600
7.00 150
7.10 0
7.20 200
7.50 400
7.30 1000
6.85 300

Sample Output 1:

749.17

Sample Input 2:

50 1300 12 2
7.10 0
7.00 600

Sample Output 2:

The maximum travel distance = 1200.00

代码(已修改正确,codeup、PAT、牛客网均能AC)

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<algorithm>
using namespace std;
struct GasStation{
	double dis;//加油站离原点(杭州)的距离 
	double price;//单位油的价格 
}nodes[501];
bool cmp(GasStation a, GasStation b){
	if(a.dis!=b.dis) return a.dis<b.dis;//加油站离杭州的距离从小到大排序 
	else return a.price<b.price;//如果距离相等,则油价从小到大排序 
}
int main(){
	double Cmax, D, Davg;//Cmax是油箱容量,D是总距离,Davg是单位油走的路,N是加油站总数
	int N;
	while(scanf("%lf%lf%lf%d", &Cmax, &D, &Davg, &N) != EOF){
		double curLen, touch, curOil, cost;
		curLen = touch = curOil = cost = 0;//curLen是当前汽车距离,touch是下次要开到的距离,curOil是当前油箱的油量,cost是花费的钱 
		for(int i=0;i<N;i++) scanf("%lf%lf", &nodes[i].price, &nodes[i].dis);
		nodes[N].dis = D;//规定N是终点站,它的油价是-1 
		nodes[N].price = -1;
		sort(nodes, nodes+N, cmp);
		//for(int i=0;i<=N;i++) printf("nodes[%d].price = %.2f, nodes[%d].dis = %.0f\n", i, nodes[i].price, i, nodes[i].dis);
		int i = 0;
		while(i<N){
			if(nodes[0].dis!=0){//如果第一个加油站的距离不在起点处(不是0),那么汽车根本无法加到油 
				printf("The maximum travel distance = 0.00\n");
				break;
			}
			int mink = i;//标记最便宜加油站的下标 
			double min = nodes[i].price;//标记最便宜加油站的油价
			int len = 0;//记录是否有比加油站i更便宜的加油站(len=0则没有,len=1则有) 
			//////////贪心选取加油站////////// 
			if(nodes[i+1].dis>nodes[i].dis+Cmax*Davg){//如果范围内没有加油站,则把油加满,能跑多少是多少 
				printf("The maximum travel distance = %.2f\n", nodes[i].dis+Cmax*Davg);
				break;
			}
			else{
				for(int k=i+1;;k++){//从i的下一个位置开始寻找是否有更便宜的加油站
					if(nodes[k].dis>nodes[i].dis+Cmax*Davg) break;//在[nodes[i].dis , nodes[i].dis+Cmax*Davg]内考虑贪心
					if(k==N) break;//到终点了,也要break掉 
					if(nodes[k].price<min&&nodes[k].price>=0){//如果该加油站的油价比本身更便宜,则更新min的值(并且nodes[k].price的值要>0,否则终点站会参与比较)  
						min = nodes[k].price;
						mink = k;
						len = 1;
						break; //找到更便宜的加油站之后直接break掉,因为要挑选距离最近的便宜的加油站 
					}
				}
			}
			if(len==0&&i<N-1){//如果找不到比本身更便宜的加油站,并且i不是最后一个加油站,就开始找次便宜的加油站(这里不需要考虑最近还是最远的问题,因为用的油肯定是本身加油站最便宜的油)
				min = nodes[i+1].price;
				mink = i+1;
				for(int x=i+1;;x++){
					if(nodes[x].dis>nodes[i].dis+Cmax*Davg) break;
					if(x==N) break;
					if(nodes[x].price<=min&&nodes[x].price>=0){//如果nodes[i].price = 0的话,不加等号就找不到下一个油价是0的加油站了 
						min = nodes[x].price;
						mink = x;
					}
				}
			}
			if(len==0&&i==N-1){//如果没有比本身更便宜的加油站,并且i是最后一个加油站 
				if(D<=nodes[i].dis+Cmax*Davg){//如果范围内有终点,则加油加到正好能跑到终点的油量 
					touch = D;
					cost += ((D-nodes[i].dis)/Davg-curOil)*nodes[i].price;
					curOil = (D-nodes[i].dis)/Davg;
					i = N;
					printf("%.2f\n", cost);
					break;
				}
			} 
			//////////贪心加油策略////////// 
			if(min>=nodes[i].price){//如果当前加油站本身就是最便宜的,那就把油箱加满,如果是最后一个加油站,油箱加到能开到终点就行
				//cost=(需要的油量-当前剩余的油量)*油价
				//curoil=需要的油量(即加完油之后达到需求油量) 
				if(D<=nodes[i].dis+Cmax*Davg){//如果本身最便宜,且终点站又在一次行程的范围内,那么只要加到能跑到终点的油量即可 
					touch = D;
					cost += ((D-nodes[i].dis)/Davg-curOil)*nodes[i].price;//注意这里要减去当前油量curOil
					curOil = (D-nodes[i].dis)/Davg;
					i = N;
					printf("%.2f\n", cost);
					break;
				}
				else{//否则就把最便宜的油加满 
					touch = nodes[mink].dis;
					cost += (Cmax-curOil)*nodes[i].price;//注意这里要减去当前油量curOil
					curOil = Cmax;
					i = mink;//开到到次便宜的加油站(到次便宜的加油站时,油箱应该还有剩余)
				}
			}
			else{//如果有更便宜的加油站,那么只需要把油加到能跑到那个加油站即可(到那个加油站时,油箱应该是空的)
				touch = nodes[mink].dis;
				cost += ((nodes[mink].dis-nodes[i].dis)/Davg-curOil)*nodes[i].price;//这里也要减去当前油量, (nodes[mink].dis-nodes[i].dis)/Davg只是需要的总油量 
				curOil = (nodes[mink].dis-nodes[i].dis)/Davg;
				i = mink;//开到mink的加油站 
			}
			curOil -= (touch-curLen)/Davg;//开车 
			curLen = touch;
		}
	} 
	return 0;
} 

问题 D: Repair the Wall

题目描述
Long time ago , Kitty lived in a small village. The air was fresh and the scenery was very beautiful. The only thing that troubled her is the typhoon.
When the typhoon came, everything is terrible. It kept blowing and raining for a long time. And what made the situation worse was that all of Kitty’s walls were made of wood.
One day, Kitty found that there was a crack in the wall. The shape of the crack is
a rectangle with the size of 1×L (in inch). Luckly Kitty got N blocks and a saw(锯子) from her neighbors.
The shape of the blocks were rectangle too, and the width of all blocks were 1 inch. So, with the help of saw, Kitty could cut down some of the blocks(of course she could use it directly without cutting) and put them in the crack, and the wall may be repaired perfectly, without any gap.
Now, Kitty knew the size of each blocks, and wanted to use as fewer as possible of the blocks to repair the wall, could you help her ?
输入
The problem contains many test cases, please process to the end of file( EOF ).
Each test case contains two lines.
In the first line, there are two integers L(0<L<1000000000) and N(0<=N<600) which
mentioned above.
In the second line, there are N positive integers. The ith integer Ai(0<Ai<1000000000 ) means that the ith block has the size of 1×Ai (in inch).
输出
For each test case , print an integer which represents the minimal number of blocks are needed.
If Kitty could not repair the wall, just print “impossible” instead.
样例输入

2 2
12 11 
14 3
27 11 4 
109 5
38 15 6 21 32 
5 3
1 1 1

样例输出

1
1
5
impossible

思路
这个问题其实可以简化为,一段给定长度的线段,然后又给你一些小线段,看看需要用到多少小线段才能达到大线段的长度(因为题目中不管是裂缝的宽度还是砖块的宽度都是1,所以完全可以不用考虑第二维的情况,将问题简化成一维),那么这题的贪心就比较简单了,肯定每次是往大了挑,只要长度等于或者超出就能完成所需的任务。
需要注意的是,这里的线段长度和小线段长度都能到109,是大于231-1的,所以要定义成long long型。
代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<algorithm>
using namespace std;
bool cmp(long long a, long long b){
	return a>b;//从大到小排序 
}
long long tmp[601];
int main(){
	long long L;
	int N;
	int sum = 0;
	while(scanf("%d%d", &L, &N) != EOF){
		for(int i=0;i<N;i++) scanf("%d", &tmp[i]);
		sort(tmp, tmp+N, cmp);
		int curL = L;
		for(int i=0;i<N;i++){
			if(curL<=0) break;
			curL -= tmp[i];
			sum++;
		}
		if(curL>0) printf("impossible\n");
		else printf("%d\n", sum);
		sum = 0;
		memset(tmp, 0, sizeof(tmp));
	} 
	return 0;
} 

问题 E: FatMouse’s Trade

题目描述
FatMouse prepared M pounds of cat food, ready to trade with the cats guarding the warehouse containing his favorite food, JavaBean.
The warehouse has N rooms. The i-th room contains J[i] pounds of JavaBeans and requires F[i] pounds of cat food. FatMouse does not have to trade for all the JavaBeans in the room, instead, he may get J[i]* a% pounds of JavaBeans if he pays F[i]* a% pounds of cat food. Here a is a real number. Now he is assigning this homework to you: tell him the maximum amount of JavaBeans he can obtain.
输入
The input consists of multiple test cases. Each test case begins with a line containing two non-negative integers M and N. Then N lines follow, each contains two non-negative integers J[i] and F[i] respectively. The last test case is followed by two -1’s. All integers are not greater than 1000.
输出
For each test case, print in a single line a real number accurate up to 3 decimal places, which is the maximum amount of JavaBeans that FatMouse can obtain.
样例输入

4 2
4 7
1 3
5 5
4 8
3 8
1 2
2 5
2 4
-1 -1

样例输出

2.286
2.500

思路
这题可以简化一下,所谓的猫粮就是钱,所谓的咖啡豆就是你要用钱去买的货物,那么这个问题就是问,在持有固定钱的前提下,如何让收益最大化。
我的思路就是先把每种情况的单价算出来(即F[i]/J[i],单位:猫粮/咖啡豆),然后把单价从小到大排序,一个个买过去,如果没钱就break掉即可。
代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<algorithm>
using namespace std;
struct javabean{
	double J;
	double F;
	double UnitPrice;
}tmp[1001];
bool cmp(javabean a, javabean b){
	return a.UnitPrice<b.UnitPrice;
}
int main(){
	double M;
	int N;
	while(scanf("%lf%d", &M, &N) != EOF){
		double sum, curM;
		sum = 0;//sum是能买到的咖啡豆总量 
		curM = M;//curM是持有的猫粮数量 
		if(M==-1&&N==-1) break;
		for(int i=0;i<N;i++) scanf("%lf%lf", &tmp[i].J, &tmp[i].F);
		for(int i=0;i<N;i++) tmp[i].UnitPrice = tmp[i].F/tmp[i].J;//计算每间屋子的咖啡豆单价
		sort(tmp, tmp+N, cmp);//对单价从小到大排序 
		for(int i=0;i<N;i++){
			if(curM<=0) break;//没钱买咖啡豆了,break 
			if(curM/tmp[i].UnitPrice<=tmp[i].J){//如果可购买的咖啡豆<=供应的咖啡豆 
				sum += curM/tmp[i].UnitPrice;
				curM -= sum*tmp[i].UnitPrice;
			}
			else{//如果可购买的咖啡豆>供应的咖啡豆 
				sum += tmp[i].J;
				curM -= tmp[i].F;
			}
		}
		printf("%.3f\n", sum);
	} 
	return 0;
} 

问题 F: 迷瘴

题目描述
小明正在玩游戏,他控制的角色正面临着幽谷的考验——
幽谷周围瘴气弥漫,静的可怕,隐约可见地上堆满了骷髅。由于此处长年不见天日,导致空气中布满了毒素,一旦吸入体内,便会全身溃烂而死。
幸好小明早有防备,提前备好了解药材料(各种浓度的万能药水)。现在只需按照配置成不同比例的浓度。
现已知小明随身携带有n种浓度的万能药水,体积V都相同,浓度则分别为Pi%。并且知道,针对当时幽谷的瘴气情况,只需选择部分或者全部的万能药水,然后配置出浓度不大于 W%的药水即可解毒。
现在的问题是:如何配置此药,能得到最大体积的当前可用的解药呢?
特别说明:由于幽谷内设备的限制,只允许把一种已有的药全部混入另一种之中(即:不能出现对一种药只取它的一部分这样的操作)。
输入
输入数据的第一行是一个整数C,表示测试数据的组数;
每组测试数据包含2行,首先一行给出三个正整数n,V,W(1<=n,V,W<=100);
接着一行是n个整数,表示n种药水的浓度Pi%(1<=Pi<=100)。
输出
对于每组测试数据,请输出一个整数和一个浮点数;
其中整数表示解药的最大体积,浮点数表示解药的浓度(四舍五入保留2位小数);
如果不能配出满足要求的的解药,则请输出0 0.00。
样例输入

2
1 35 68
1 
2 79 25
59 63 

样例输出

35 0.01
0 0.00

思路
这题的贪心也比较简单,首先要知道一点:两种不同的浓度混合的话,最终的浓度肯定在两者浓度之间。
所以,为了得到最大体积且要保证浓度小于等于W,我们可以把浓度从小到大排序,从浓度最小的药水开始混合,一旦混合到大于W之后就退回取上一次的(因此我们混合完后需要判断是否可行,如果可行,一定要记录一下当前值,否则break的时候会丢失,如果不行就break)。
当然,如果浓度从小到大排好序之后第一瓶药的浓度已经大于W,那么也就没必要再混合了,直接输出“0 0.00”即可。
代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<algorithm>
using namespace std;
struct potion{//每瓶药水的信息 
	double V;//体积 
	double p;//浓度 
}s[101];
bool cmp(potion a, potion b){
	return a.p<b.p;//浓度从小到大排序 
}
int main(){
	int C;
	while(scanf("%d", &C) != EOF){
		while(C--){
			int n;
			double tmpV, W, fV, fW, rz, rj;//fV是解药的体积,fW是解药的浓度,rz是溶质,rj是体积总量 
			fV = fW = rz = rj = 0;
			scanf("%d%lf%lf", &n, &tmpV, &W); 
			for(int i=0;i<n;i++) s[i].V = tmpV;
			for(int i=0;i<n;i++) scanf("%lf", &s[i].p);
			sort(s, s+n, cmp);
			if(s[0].p>W) printf("0 0.00\n");//如果最小的浓度已经比W大,说明无解 
			else{
				for(int i=0;i<n;i++){
					rz += s[i].V*s[i].p;//先混合一下 
					rj += s[i].V;
					if(rz/rj<=W){
						fV = rj;//如果混合以后方案可行,那么更新一下fV和fW 
						fW = (rz/rj)/100;
						continue;
					}
					else break;//如果混合之后已经>W了,说明只能取上一次的	
				}
				printf("%.0f %.2f\n", fV, fW);
			}
		}		
	} 
	return 0;
}

问题 G: 找零钱

题目描述
小智去超市买东西,买了不超过一百块的东西。收银员想尽量用少的纸币来找钱。
纸币面额分为50 20 10 5 1 五种。请在知道要找多少钱n给小明的情况下,输出纸币数量最少的方案。 1<=n<=99;
输入
有多组数据 1<=n<=99;
输出
对于每种数量不为0的纸币,输出他们的面值*数量,再加起来输出
样例输入

25
32

样例输出

20*1+5*1
20*1+10*1+1*2

思路
这题的贪心思路也是很常见的,要纸币数量最少,那就先尽量找面值大的输出,如果没有就往下继续找面值次大的输出。
代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<algorithm>
using namespace std;
int hashtable[51]={0};//记录对应面值要的纸币数(下标是面值,内容是数量) 
int main(){
	int n;
	while(scanf("%d", &n) != EOF){
		while(1){
			if(n>=50){
				n -= 50;
				hashtable[50]++;
			}
			else if(n>=20){
				n -= 20;
				hashtable[20]++;
			}
			else if(n>=10){
				n -= 10;
				hashtable[10]++;
			}
			else if(n>=5){
				n -= 5;
				hashtable[5]++;
			}
			else if(n>0){
				n -= 1;
				hashtable[1]++;
			}
			else break;
		}
		int cnt = 0;
		for(int i=50;i>=1;i--){
			if(hashtable[i]>0){
				if(cnt==0){
					printf("%d*%d", i, hashtable[i]);
				}
				else printf("+%d*%d", i, hashtable[i]);//如果不是第一个元素,前面带上加号 
				cnt++;
			}
		}
		printf("\n");
		memset(hashtable, 0, sizeof(hashtable));
	}
	return 0;
} 

小结

这次碰到的最难的问题就是PAT的To Fill or Not to Fill了,一开始看提示也完全没看懂是什么意思,于是我花了一晚上和一早上的功夫,把贪心实现的过程写了下来,然后自己再去慢慢把思路翻译成代码,然后过一下测试样例,再根据样例给出的问题慢慢完善自己的代码。

这里我还是比较建议去找PAT上的样例过一遍思路,那个样例几乎所有情况都包含了(就是我图里画出来的那个),codeup上的样例给的太简单了,而且交了三个网站的代码的我得出了这一题的一个结论:codeup的测试点最简单,PAT其次,牛客网的最难通过(之前PAT和牛客网都差一个样例没过我以为是起点没有加油站的情况忘记考虑了,谁知道改了之后只有PAT AC了,牛客网还是case通过率90%……)。

总的来说,贪心主要能分为普通的贪心和区间的贪心,区间的贪心很简单,用模板来实现基本上都一样,而普通的贪心就不好说了,我们需要具体问题具体分析,而不是说一个代码就能适合所有情况。我个人认为,贪心最重要的就是掌握它的思维——局部最优,则全局最优,至于如何熟练使用,那就要多靠训练啦~

发布了54 篇原创文章 · 获赞 27 · 访问量 4999

猜你喜欢

转载自blog.csdn.net/weixin_42257812/article/details/105036655