牛客网——爱偷懒的小明(Java+排序)

题目

临近期末考试的时间,就是莘莘学子开始担心自己学分的时候。
怠惰的小明这学期过得非常慵懒,为了让小明不挂科,辅导员规定小明的各个科目平时分的总和必须大于等于r。
三天打鱼两天晒网的小明的平时分不可能这么高,所以不得不补交一些作业。
小明这学期有n门课,对于第i门课,小明原有的平时分为ai,任课老师规定,小明每补交bi次作业,老师给他的第i 门课的平时分加1分。第i门课的平时分上限为ci,小明的分数达到上限后不能再继续加分。
爱偷懒的小明想问问你,最少他要补交几次作业才可以使得他的平时分总和大于等于r。

输入描述:第一行包含两个整数n, r,(1 <= n <= 100, r <= 1000)表示小明的学科数以及老师规定的平时分总和。接下来n行,每行包含3个整数 ai, bi ,ci(1 <= ai <= ci <= 1000, 1 <= bi <= 1000),分别表示小明原有的平时分,第i门课加一分所需要补交作业的次数以及第i门课的平时分上限,数据保证 ∑ci 大于 r
输出描述:最少需要补交作业的次数

输入:
2 30
10 3 40
10 2 40
输出:20
小明补交第2门课程20次作业,课程的平时分总和变为20 + 10 = 30,达到了老师的要求 。

分析

1.因为该题涉及多个变量,且这些变量之间存在一定的关系,且这些变量都属于同一个对象的属性,所以采用封装的思想,将这些变量,都定义在一个类中。实例化类时,对象自然有这些属性。
2.因为这些变量之间存在一定的关系,根据题意,进行升序排列,所以让该类继承Comparable,并重写compareTo方法。
3.在主函数里面循环生成类对象,并加入list,通过list,取出元素,依次进行补交作业次数的判断。同时也要用一个变量存储当前平时分的总和,为后面的计算做铺垫。
4.因为每一门课程平时分有上限,所有应考虑清楚,如何进行计算。要满足不超过上限,又要找到最少的补交次数,那么就可以贪心做:

  • 如果所需要的分数<=当前该科最大分数-已有的分数,即该科可以补交的最大分数,说明可以只用补交这一科就能过,不需要继续补交了。
  • 如果所需要的分数>当前该科最大分数-已有的分数,就将该科能补交的最大次数求出来,用sum累加;同时所需分数减对应的分值。继续找下一科。

细节

  1. 我用的list存储Work类的对象,尽管我已经重写了compareTo(),但是那只是定义了一个排序规则,并没有排好序,用list存储之后,还得再调用Collections.sort()方法进行排序,而且后面还得循环遍历list才能取出对象,会增大时间复杂度,所以代码改进,可以使用PriorityQueue;
  2. 所需要的分数,应该是额外的补加,我一开始想成了:“所需要的分数+已有的分数<=当前该科最大分数”,但这道题求的是补的~补的分数!然而我初始化的时候定义成

int stillNeed = r - cur;

那么相当于,已经减去了“已有的分数”,现在又重新加上,能解决什么问题??
我们要求的是“最少他要补交几次作业才可以使得他的平时分总和大于等于r。”注意是补的,补的意思就是你还得额外加入。
3. 一门课最多只能加到maxScore,加满了,就不能再修了,所以要保证一科一个最大补分,完了就得下一科,不要在一科上面循环处理。

代码

我第一次写的:

public class MainDSelf {
	public static void main(String[] args) {
		Scanner input = new Scanner(System.in);
		int n = input.nextInt();// 学科数
		int r = input.nextInt();// 规定分数
		List<HomeWork> list = new ArrayList<>();
		int cur = 0;// 记录当前平时分总和
		for (int i = 0; i < n; i++) {
			int preScore = input.nextInt();
			int need = input.nextInt();
			int maxScore = input.nextInt();
			HomeWork work = new HomeWork(preScore, need, maxScore);
			list.add(work);
			cur += work.preScore;
		}
		Collections.sort(list);
		int sum = 0;// 提交作业的最小总次数
		int stillNeed = r - cur;
		for (int i = 0; i < list.size(); i++) {
			HomeWork obj = list.get(i);
			while (stillNeed > 0) {
				if (stillNeed <= obj.maxScore - obj.preScore) {
					sum += stillNeed * obj.need;
					stillNeed = 0;
				} else {
					int temp = obj.maxScore - obj.preScore;
					sum += temp * obj.need;
					stillNeed -= temp;
				}
				break;//这样做不好

			}
		}
		System.out.println(sum);
	}

}

class HomeWork implements Comparable<HomeWork> {
	int preScore;// 已有的平时分
	int need;// 加1分需要补交的作用
	int maxScore;// 该科平时分最大上线

	public HomeWork(int preScore, int need, int maxScore) {
		this.preScore = preScore;
		this.need = need;
		this.maxScore = maxScore;
	}

	@Override
	public int compareTo(HomeWork o) {
		// TODO Auto-generated method stub
		return this.need - o.need;
	}

}

代码改进(看这个,理解清楚这个就好了)

public class MainD {
	public static void main(String[] args) {
		Scanner input = new Scanner(System.in);
		int n = input.nextInt();// 学科数
		int r = input.nextInt();// 规定平时分总和
		int cur = 0;
		PriorityQueue<Work> queue = new PriorityQueue<>();
		for (int i = 0; i < n; i++) {
			int preScore = input.nextInt();
			int cost = input.nextInt();
			int maxScore = input.nextInt();
			Work work = new Work(preScore, cost, maxScore);
			cur += preScore;// 记录所有科目的现有学分
			queue.add(work);// 小顶堆
		}
		r = r - cur;// 看还需要多少学分
		int ans = 0;
		while (!queue.isEmpty() && r > 0) {
			Work temp = queue.poll();
			if (r <= temp.maxScore - temp.preScore) {
				ans += r * temp.cost;
				r = 0;
			} else {
				int t = temp.maxScore - temp.preScore;
				ans += t * temp.cost;
				r = r - t;
			}
		}
		System.out.println(ans);
	}
}

class Work implements Comparable<Work> {
	int preScore;// 之前的成绩
	int cost;// 提交的次数,才能够1分
	int maxScore;// 最大的成绩

	public Work(int preScore, int cost, int maxScore) {
		this.preScore = preScore;
		this.cost = cost;
		this.maxScore = maxScore;
	}

	@Override
	public int compareTo(Work o) {
		if (this.cost != o.cost) {
			return this.cost - o.cost;
		}
		return (o.maxScore - o.preScore) - (this.maxScore - this.preScore);
	}
}

个人觉得:
compareTo()就下面这个就可以了。

@Override
	public int compareTo(HomeWork o) {
		// TODO Auto-generated method stub
		return this.need - o.need;
	}

两个代码都能过~~

反思

第一个动手操作这种类型的题,以后得多练习!!
end.

链接:https://ac.nowcoder.com/acm/contest/10293/D
来源:牛客网

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值