#题解 P1190 接水问题

题目

题目描述

学校里有一个水房,水房里一共装有mm个龙头可供同学们打开水,每个龙头每秒钟的供水量相等,均为1 1

现在有n n 名同学准备接水,他们的初始接水顺序已经确定。将这些同学按接水顺序从 11n n 编号,ii 号同学的接水量为 wiw_i。接水开始时,11 m m 号同学各占一个水龙头,并同时打开水龙头接水。当其中某名同学j j 完成其接水量要求wj w_j后,下一名排队等候接水的同学 kk马上接替 jj 同学的位置开始接水。这个换人的过程是瞬间完成的,且没有任何水的浪费。即jj 同学第 xx 秒结束时完成接水,则k k 同学第 x+1x+1 秒立刻开始接水。若当前接水人数 nn’不足 mm,则只有 nn’个龙头供水,其它 mnm-n’个龙头关闭。

现在给出 nn 名同学的接水量,按照上述接水规则,问所有同学都接完水需要多少秒。

输入格式

112 2 个整数 nnmm,用一个空格隔开,分别表示接水人数和龙头个数。

22nn 个整数w1,w2,,wn w_1,w_2,…,w_n,每两个整数之间用一个空格隔开,wiw_i表示i i 号同学的接水量。

输出格式

11 个整数,表示接水所需的总时间。

输入输出样例

输入 #1
5 3 
4 4 1 2 1 
输出 #1
4
输入 #2
8 4 
23 71 87 32 70 93 80 76 
输出 #2
163

说明/提示

【输入输出样例 1 说明】

11 秒,33 人接水。第 11 秒结束时,1,2,31,2,3 号同学每人的已接水量为 1,31,3 号同学接完水,44 号同学接替 33 号同学开始接水。

22 秒,33 人接水。第2 2 秒结束时,1,21,2 号同学每人的已接水量为 2,42,4 号同学的已接水量为1 1

33 秒,33 人接水。第3 3 秒结束时,1,21,2 号同学每人的已接水量为 3,43,4 号同学的已接水量为 2。44 号同学接完水,55 号同学接替4 4 号同学开始接水。

4 4 秒,33 人接水。第 44 秒结束时,1,21,2 号同学每人的已接水量为 4,54,5 号同学的已接水量为1 11,2,51,2,5 号同学接完水,即所有人完成接水的总接水时间为 44 秒。

【数据范围】

1n10000,1m1001≤n≤10000,1≤m≤100mn m≤n

1wi1001≤w_i≤100

实现

这题乍一看会用模拟来做,一秒一秒得模拟,而这种方法实在太慢,有一个好办法,那就是把正在使用水龙头的剩余最少的剩余水量作为每一次模拟的时间,而非一秒一秒模拟。

具体思路是首先输入,将前mm个赋值到水龙头(sltslt)的结构体数组中,排序。接下来while循环,当所有人都开始接水时结束,while循环内time1time1负责计算时间总和,每次加上剩余最少的那个的水量,jianjian负责记录那个人的剩余水量(如果不加后面就不对了,原变量会被覆盖)。while循环中for循环,将每个水量都减去jianjian,if语句负责将没有剩余,也就是接好的人替换到下一个,nownow负责记录下一个等待加水的人。while循环最后,排序。while循环结束,意味着所有人都在接水或已经接好水,此时,只需加上在加水的人中剩余最多的水量即可。

说干就干,很快就可以写出如下代码:

#include <bits/stdc++.h>
using namespace std;
int n,m;
int w[10005];
typedef struct node{
    int water;
    int number;
}node;
node slt[105];
int now=0;
int time1 = 0;
int jian;
bool cmp(node a,node b){
    return a.water < b.water;
}
int main(){
    cin >> n >> m;
    for(int i = 0; i < n; i++){
        cin >> w[i];
    }

    for(int i = 0; i < m; i++){
        slt[i].water = w[i];
        slt[i].number = i;
    }
    now = m;
    sort(slt,slt+m,cmp);
    while (now<=n){
        time1+=slt[0].water;
        jian = slt[0].water;
        for(int i = 0; i < m; i++){
            slt[i].water -= jian;
            if(slt[i].water<=0){
                slt[i].water=w[now];
                slt[i].number=now;
                now++;
            }
        }
        sort(slt,slt+m,cmp);
    }
    sort(slt,slt+m,cmp);
    time1 += slt[m-1].water;
    cout << time1;
    return 0;
}

主要讲一下几个坑点:

  1. while循环里的条件
  2. while循环中time1time1累加的位置
  3. 最后的加法不能忘。