一本通1233 接水问题
【题目描述】
学校里有一个水房,水房里一共装有m个龙头可供同学们打开水,每个龙头每秒钟的供水量相等,均为1。
现在有n名同学准备接水,他们的初始接水顺序已经确定。将这些同学按接水顺序从1到n编号,i号同学的接水量为wi。接水开始时,1到m号同学各占一个水龙头,并同时打开水龙头接水。当其中某名同学j完成其接水量要求wj后,下一名排队等候接水的同学k马上接替j同学的位置开始接水。这个换人的过程是瞬间完成的,且没有任何水的浪费。即j同学第x秒结束时完成接水,则k同学第x+1 秒立刻开始接水。 若当前接水人数n’不足m,则只有n’个龙头供水,其它m-n’个龙头关闭。
现在给出n名同学的接水量,按照上述接水规则,问所有同学都接完水需要多少秒。
【输入】
第1行2个整数n和m,用一个空格隔开,分别表示接水人数和龙头个数。
第2 行n个整数 w1、w2、……、wn,每两个整数之间用一个空格隔开,wi表示 i 号同学的接水量。
【输出】
输出只有一行,1个整数,表示接水所需的总时间。
【输入样例】
5 3 4 4 1 2 1
【输出样例】
4
【提示】
样例输入#2:
8 4
23 71 87 32 70 93 80 76
样例输出#2:
163
提示:
输入输出样例1解释:
第1秒,3人接水。第1秒结束时,1、2、3号同学每人的已接水量为1,3号同学接完水,4号同学接替3号同学开始接水。
第2秒,3人接水。第2秒结束时,1、2号同学每人的已接水量为2,4号同学的已接水量为1。
第3秒,3人接水。第3秒结束时,1、2号同学每人的已接水量为3,4号同学的已接水量为2。4号同学接完水,5号同学接替4号同学开始接水。
第4秒,3人接水。第4秒结束时,1、2号同学每人的已接水量为4,5号同学的已接水量为1。1、2、5号同学接完水,即所有人完成接水。
总接水时间为4秒。
思路:一开始我看到这个题感觉就是一道大水题,但是后来我才发现这个题的顺序是不能改变的,必须按顺序接水,我也不知道这样跟贪心有什么关系,应该是一道模拟题才对。一个个接水就要保证一个人接完水才能换下一个人接,而且要按顺序接,那么交换即可。弄一个指针,一直指着下一个要接水的人,等一个人接完水交换就行了。那么循环结束的条件是什么?我想了好久。其实很简单,所有人接完水,当然就结束了,但是按照我这个思路写代码其实不好验证什么时候结束,所以我想,最后一波接水,一定是除了正在接水的人都接完水了,那么我只需要让时间最长的那个人接完,所有人也就都接完了,那么我让答案加上他所需要的时间就行了,然后我这清奇的思路居然A了。
代码:
#include<cstdio>
#include<math.h>
#include<algorithm>
#include<cstring>
using namespace std;
int n,m,ans,sum,t;
int minn=0x4f;
int w[10010],a[10010];
int cmp(int x,int y)
{
return x>y;
}
int main()
{
scanf("%d%d",&n,&m);
int l=m;//这是那个指针,指向下一个要接水的人
for(int i=1;i<=n;i++)
scanf("%d",&w[i]);
while(1){//这里我while(1)是因为我也不知道什么时候会停下来,所以在找到结束条件的时候我输出答案再加一个return 0即可
minn=0x4f;//每次循环都要初始化为最大值
for(int i=1;i<=m;i++)
{
minn=min(minn,w[i]);
if(minn==0)//这里注意了,就是结束条件,如果当中的最小值为0,也就是除了这m个人(其实是m-1个人,有一个0)所有人都已经接完水了,那么加上其中最慢的那个人所需要的时间也就是最大值,输出答案即可
{
sort(w+1,w+m+1,cmp);//我用的排序找最大值
ans+=w[1];//w[1]就是最大值
cout<<ans;//输出之后return 0,不然while(1)死循环
return 0;
}
}
for(int i=1;i<=m;i++)//如果没有到最后一波,那么找到其中的最小值,先抬走最快的那个人,让下一个人接水,也就是指针指着的人
{
w[i]-=minn;//所有人都要减去这个最小值,因为大家是一起接水的
if(w[i]==0)//找到那个被抬走的人
{
swap(w[i],w[l+1]);//跟下一个人换位置
l++;//指针++
}
}
ans+=minn;//接水当然要花时间,所以加上
}
return 0;
}//没了