接水問題

Aaron-mhx發表於2020-11-21

題目

題目描述

學校裡有一個水房,水房裡一共裝有mmm個龍頭可供同學們開啟水,每個龍頭每秒鐘的供水量相等,均為1 11

現在有n n n名同學準備接水,他們的初始接水順序已經確定。將這些同學按接水順序從 111n n n編號,ii i號同學的接水量為 wiw_iwi。接水開始時,11 1m mm 號同學各佔一個水龍頭,並同時開啟水龍頭接水。當其中某名同學j j j完成其接水量要求wj w_jwj後,下一名排隊等候接水的同學 kkk馬上接替 jjj 同學的位置開始接水。這個換人的過程是瞬間完成的,且沒有任何水的浪費。即jjj 同學第 xxx 秒結束時完成接水,則k kk 同學第 x+1x+1x+1 秒立刻開始接水。若當前接水人數 nnn’不足 mmm,則只有 nnn’個龍頭供水,其它 m−nm-nmn’個龍頭關閉。

現在給出 nnn 名同學的接水量,按照上述接水規則,問所有同學都接完水需要多少秒。

輸入格式

1112 22 個整數 nnnmmm,用一個空格隔開,分別表示接水人數和龍頭個數。

222nnn 個整數w1,w2,…,wn w_1,w_2,…,w_nw1,w2,,wn,每兩個整數之間用一個空格隔開,wiw_iwi表示i i i號同學的接水量。

輸出格式

111 個整數,表示接水所需的總時間。

輸入輸出樣例

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

說明/提示

【輸入輸出樣例 1 說明】

111 秒,33 3人接水。第 11 1秒結束時,1,2,31,2,3 1,2,3號同學每人的已接水量為 1,31,3 1,3號同學接完水,44 4號同學接替 333 號同學開始接水。

222 秒,33 3人接水。第2 22 秒結束時,1,21,2 1,2號同學每人的已接水量為 2,42,4 2,4號同學的已接水量為1 11

333 秒,33 3人接水。第3 33 秒結束時,1,21,21,2 號同學每人的已接水量為 3,43,43,4 號同學的已接水量為 2。444 號同學接完水,555 號同學接替4 4 4號同學開始接水。

4 44 秒,33 3人接水。第 44 4秒結束時,1,21,21,2 號同學每人的已接水量為 4,54,5 4,5號同學的已接水量為1 111,2,51,2,51,2,5 號同學接完水,即所有人完成接水的總接水時間為 444 秒。

【資料範圍】

1≤n≤10000,1≤m≤1001≤n≤10000,1≤m≤1001n10000,1m100m≤n m≤nmn

1≤wi≤1001≤w_i≤1001wi100

實現

這題乍一看會用模擬來做,一秒一秒得模擬,而這種方法實在太慢,有一個好辦法,那就是把正在使用水龍頭的剩餘最少的剩餘水量作為每一次模擬的時間,而非一秒一秒模擬。

具體思路是首先輸入,將前 m m m個賦值到水龍頭( s l t slt slt)的結構體陣列中,排序。接下來while迴圈,當所有人都開始接水時結束,while迴圈內 t i m e 1 time1 time1負責計算時間總和,每次加上剩餘最少的那個的水量, j i a n jian jian負責記錄那個人的剩餘水量(如果不加後面就不對了,原變數會被覆蓋)。while迴圈中for迴圈,將每個水量都減去 j i a n jian jian,if語句負責將沒有剩餘,也就是接好的人替換到下一個, n o w now now負責記錄下一個等待加水的人。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迴圈中 t i m e 1 time1 time1累加的位置
  3. 最後的加法不能忘。