[洛谷][P2094]运输(Java)(贪心)

原题链接

题目描述

现在已知N件商品,和搬运它们其中每一件的费用。现在搬家公司老板Mr.sb决定让我们每次任意选取2件商品。然后这2件商品只算一件商品的费用。但是这个商品的搬运费用是将选出的2个商品的费用之和除以k的运算结果。如此反复。直到只收一件商品的钱。这个就是商店要付的费用。掌柜的想尽可能的少付钱,以便将更多的钱捐给希望工程。所以请你帮他计算一下最少只用付多少钱。

【输入格式】trans.in

【输出格式】

【样例输入】trans.out

【样例输出】

1

输入输出格式

输入格式:

n,k w1,w2.....wn(每一件物品搬运费)

输出格式:

一个数 最少付多少钱

 

输入输出样例

输入样例#1: 复制

5 2
1 2 3 4 5

输出样例#1: 复制

1

说明

【数据规模】

n、k、wi均为非负数

n和k<=10000


解题思路:

这题的描述看的我想骂街,表达非常不清楚。。。题意是给你一堆数字,每次你能选出两个,把他们相加除以 k ,再放回去,,最后剩下一个时候,剩下的这个值最小是多少……

看懂题之后想到的就是贪心了,因为 k 是固定的,不妨假设是 2 。

那么题就变成了,拿出两数相加除2再放回去,最后成一个时,值最小是多少。肯定是最小的数先加小啊,

举个例子吧【1,3,4,8,9】,先看看每次选最小的【((1+3)/2)=2,4,8,9】,再选最小的两个【((2+4)/2)=3,8,9】,不难看出,1+3除了两次 2 。有点像二分法的感觉,每次都取小的数,总体就向小数方向移动,,要是取大的数,那整体就向大数移动了。

所以用一个优先级队列,每次取两个小的数,计算后再放回,直到剩余一个。

 

反思错误:

①一开始想取大的数,认为先用大的数,那么被除的次数越多结果就越小了,结果发现整体是向大数移动的。

 

Java代码(用的模板,所以看着多,实际代码很少):

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.StringTokenizer;

public class Main {
	public static void main(String[] args) {
//		long sta = System.nanoTime();

		InputStream is = System.in;
		OutputStream os = System.out;

		IN cin = new IN(is);
		PrintWriter cout = new PrintWriter(os);

		SO so = new SO();
		so.solution(cin, cout);

//		long end = System.nanoTime();
//		cout.println("耗时:" + (double)(end-sta)/1e6 + "ms");

		cout.close();
	}

	static final int MOD = (int)1e9 + 7;
	//实际代码开始的类--------------------------------------------------
	static class SO {
		void solution(IN cin, PrintWriter cout) {
			int n = cin.nextInt(), k = cin.nextInt();
			Queue<Integer> pq = new PriorityQueue<Integer>((a1,a2)->a2-a1);
			for(int i=0;i<n;++i) {
				pq.add(cin.nextInt());
			}
			int cur = 0;
			while(n>1) {
				int a = pq.remove(), b = pq.remove();
				cur = (a+b)/k;
				pq.add(cur);
				--n;
			}
			cout.println(pq.remove());
		}//end solution
	}//end SO
	
	//以下是快读部分
	static class IN {
		private BufferedReader reader;
		private StringTokenizer tokenizer;

		IN(InputStream is) {
			reader = new BufferedReader(new InputStreamReader(is), 32768);
			tokenizer = null;
		}
		
		public String next() {
			while (tokenizer == null || !tokenizer.hasMoreTokens()) {
				try {
					tokenizer = new StringTokenizer(reader.readLine());
				} catch (IOException e) {
					throw new RuntimeException(e);
				}
			}
			return tokenizer.nextToken();
		}

		public int nextInt() {
			return Integer.parseInt(next());
		}

		public long nextLong() {
			return Long.parseLong(next());
		}

		public double nextDouble() {
			return Double.parseDouble(next());
		}

	}
}

 

测试结果:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值