打水问题(贪心)

一、打水问题

问题描述

  N个人要打水,有M个水龙头,第i个人打水所需时间为Ti,请安排一个合理的方案使得所有人的等待时间之和尽量小。

输入格式

  第一行两个正整数N M 接下来一行N个正整数Ti。
  N,M<=1000,Ti<=1000

输出格式

  最小的等待时间之和。(不需要输出具体的安排方案)

样例输入

7 3
3 6 1 4 2 5 7

样例输出

11

提示

  一种最佳打水方案是,将N个人按照Ti从小到大的顺序依次分配到M个龙头打水。
  例如样例中,Ti从小到大排序为1,2,3,4,5,6,7,将他们依次分配到3个龙头,则去龙头一打水的为1,4,7;去龙头二打水的为2,5;去第三个龙头打水的为3,6。
  第一个龙头打水的人总等待时间 = 0 + 1 + (1 + 4) = 6
  第二个龙头打水的人总等待时间 = 0 + 2 = 2
  第三个龙头打水的人总等待时间 = 0 + 3 = 3
  所以总的等待时间 = 6 + 2 + 3 = 11

#include<iostream >
#include<algorithm>
#include<cstring>
using namespace std;
const int N=1100;
int t[N];  //每一个人打水所需时间 
int waite[N];  //存放的是每一个人需要等的时间 
int n,m; //n个人,m个水龙头
int main()
{
	cin>>n>>m;
	for(int i=0;i<n;i++) cin>>t[i]; 
	/*此题使用的是贪心思想,你可以想象一下,当你在打水的时候你是不是都在想,如果你前面的人
	 的打水时间越少你是不是就能更快的打到水了。题目要求的是最小的等待时间之和,
	 因此只需要按照这个思路去操作 即可。我们可以对所有的打水时间先进行排序,打水时间少的先打水
	,后面的人就不用等很长时间了。你可以想象一下如果你的前面是打水时间为1分钟的,你是不是要等1分钟,
	如果你的前面是打水时间为7分钟的,那你是不是要等7分钟,所以你更愿意你的前面是谁呢?显然是1分钟的呀 
	 */ 
	 sort(t,t+n);//先排序
	 /*现在我们就开始算每个人需要等待的时间是多少,
	 我的思路是 你的等待时间=前面一个人的等待时间+前面一个人的打水时间
	 然后把每个人的等待时间加起来就得到了最少的时间 
	  */ 
	
	//把n个人分别分配到m个水龙头上 
	int ans=0;  // 最小的等待时间之和
	 for(int i=0;i<n;i++)
	 {
	 	if(i<m)   //前m个人是不需要等待的,直接就可以打水了,因此等待时间为0 
	 	{
	 		waite[i]=0;
	 	}
	 	else
		{
			//你的等待时间=前面一个人的等待时间+前面一个人的打水时间
			//减m是因为要分配到m个水龙头上 
		 	waite[i]=waite[i-m]+ t[i-m];
		 } 
		 ans+=waite[i]; 
	 } 
	 cout<<ans<<endl;
	return 0;
} 

二、排队打水问题

问题描述

  有n个人排队到r个水龙头去打水,他们装满水桶的时间t1、t2………..tn为整数且各不相等,应如何安排他们的打水顺序才能使他们总共花费的时间最少?

输入格式

  第一行n,r (n<=500,r<=75)
  第二行为n个人打水所用的时间Ti (Ti<=100);

输出格式

  最少的花费时间

样例输入

3 2
1 2 3

样例输出

7 

数据规模和约定

  其中80%的数据保证n<=10

这道题和打水问题是一样的思路,只不过上一个问题求的是打水等待时间,而这一题求的是总花费的时间也就是打水时间加上等待时间。不多说直接把上面的代码修改一下就可以了。

#include<iostream >
#include<algorithm>
#include<cstring>
using namespace std;
const int N=1100;
int t[N];  //每一个人打水所需时间 
int waite[N];  //存放的是每一个人需要等的时间 
int n,m; //n个人,m个水龙头
int main()
{
	cin>>n>>m;
	for(int i=0;i<n;i++) cin>>t[i]; 
	/*此题使用的是贪心思想,你可以想象一下,当你在打水的时候你是不是都在想,如果你前面的人
	 的打水时间越少你是不是就能更快的打到水了。题目要求的是最小的等待时间之和,
	 因此只需要按照这个思路去操作 即可。我们可以对所有的打水时间先进行排序,打水时间少的先打水
	,后面的人就不用等很长时间了。你可以想象一下如果你的前面是打水时间为1分钟的,你是不是要等1分钟,
	如果你的前面是打水时间为7分钟的,那你是不是要等7分钟,所以你更愿意你的前面是谁呢?显然是1分钟的呀 
	 */ 
	 sort(t,t+n);//先排序
	 /*现在我们就开始算每个人需要等待的时间是多少,
	 我的思路是 你的等待时间=前面一个人的等待时间+前面一个人的打水时间
	 然后把每个人的等待时间加起来就得到了最少的时间 
	  */ 
	
	//把n个人分别分配到m个水龙头上 
	int ans=0;  // 最小的等待时间之和
	 for(int i=0;i<n;i++)
	 {
	 	if(i<m)   //前m个人是不需要等待的,直接就可以打水了,因此等待时间为0 
	 	{
	 		waite[i]=0;
	 	}
	 	else
		{
			//你的等待时间=前面一个人的等待时间+前面一个人的打水时间
			//减m是因为要分配到m个水龙头上 
		 	waite[i]=waite[i-m]+ t[i-m];
		 } 
	 } 
	 for(int i=0;i<n;i++)
	 {
	 	ans+=t[i]+waite[i];
	 }
	 cout<<ans<<endl;
	return 0;
} 

贪心算法打水问题中通常用于模拟最优的取水策略,假设有一个容量为V的大桶和若干个容量为W的小桶,目标是在不浪费水的情况下,通过多次将小桶装满然后倒入大桶来使大桶装满。这里是一个简单的C语言代码实现: ```c #include <stdio.h> // 定义桶的大小 #define V 80 // 大桶容量 #define W 10 // 小桶容量 // 假设总水量不超过大桶的两倍 #define TOTAL_WATER (2 * V) int canFill(int remainingWater, int smallBucket) { // 如果剩余水量小于等于一个小桶的容量,则直接用一个小桶装满 return remainingWater <= smallBucket; } int optimalPouringStrategy(int totalWater, int smallBuckets) { int i = 0, remainingWater = totalWater, waterFilled = 0; while (remainingWater > 0 && i < smallBuckets) { if (canFill(remainingWater, V)) { // 使用大桶装满 remainingWater -= V; waterFilled += V; } else { // 使用小桶尽可能多地装水,并减去溢出的部分 int smallBucketContent = min(remainingWater, W); remainingWater -= smallBucketContent; waterFilled += smallBucketContent; } i++; } return waterFilled; } int main() { int totalWater = TOTAL_WATER; int smallBuckets = 6; // 示例中的小桶数量 printf("最大可获得的水量: %d\n", optimalPouringStrategy(totalWater, smallBuckets)); return 0; } ``` 在这个代码中,`canFill()` 函数检查是否可以用一个小桶装满剩下的水,`optimalPouringStrategy()` 则根据贪心策略计算最多能从总水量中倒出多少放入大桶。注意这是一个简化版本,实际应用可能需要更复杂的情况处理。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

沐汐˃̵͈̑ᴗ˂̵͈̑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值