三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

题解:学而思编程 浇水

题解:学而思编程 浇水

【题目来源】

学而思编程:浇水

【题目描述】

皮皮和小美打算给花园里的 \(n\) 株植物浇水。
植物排成一行,编号从左到右依次从 \(1\)\(n\)。其中,第 \(i(1≤i≤n)\) 株植物的位置 \(x=i\),需要浇的水量为 \(w_i\) 升。皮皮和小美每人有一个水罐,其中皮皮的水罐容量为 \(A\) 升,小美的水罐的容量为 \(B\) 升,初始时,两个水罐都装满了水。

皮皮从左到右给植物浇水,从第 \(1\) 株植物开始。小美从右到左给植物浇水,从第 \(n\) 株植物开始。他们俩同时开始给植物浇水。

皮皮和小美各自为每株植物浇水时,每分钟浇 \(1\) 升水,也就是每过去一分钟,水罐中的水减少 \(1\) 升,植物还需要浇的水也减少 \(1\) 升。如果当前植物所需浇水量减为 \(0\),就移动到下一棵植物(对于皮皮是编号大 \(1\) 的植物,对于小美是编号小 \(1\) 的植物),移动的时间忽略不计。

如果浇水途中水罐中的水耗尽了,一个超强水泵会用 \(T\) 分钟的时间,重新灌满水罐,然后重新开始浇水。

如果某人到达一株植物时,另一个人已经先到了,那么就只让先到的人浇水。如果皮皮和小美同时到达,就让皮皮完成浇水。

请你实现一个程序,求为所有植物完成浇水的时间。

【输入】

\(1\) 行包含 \(4\) 个正整数 \(n,A,B,T\)

\(2\) 行,\(n\) 个正整数 \(w_1,w_2,…,w_n\)

【输出】

输出一行,一个整数,表示答案。

【输入样例】

5 1 9 5
7 3 2 3 2

【输出样例】

37

【核心思想】

  1. 问题分析:给定 \(n\) 株植物排成一行,每株需水量 \(w_i\)。皮皮从左到右(\(1 \to n\))、小美从右到左(\(n \to 1\))同时浇水,每人水罐容量分别为 \(A\)\(B\),浇水速度 \(1\) 升/分钟,水耗尽后需 \(T\) 分钟重新灌满。若两人到达同一株植物,先到者浇(同时到则皮皮浇)。求全部浇完的总时间。这是一个双指针模拟问题,核心在于两人独立推进,用双指针追踪各自进度,总时间取两者最大值。

  2. 算法选择

    • 双指针\(l\)\(1\) 向右,\(r\)\(n\) 向左,分别代表皮皮和小美当前处理的植物
    • 贪心调度:每次选择当前总时间较小的一方先处理下一株植物(确保先到者先浇)
  3. 关键步骤

    • 初始化:读取 \(n, A, B, T\)、需水量数组 \(w[1..n]\)
    • 辅助函数 \(water(x, X, w)\)
      • 计算当前剩余水量 \(x\) 浇灌需水量 \(w\) 所需的加水次数:\(cnt = \lceil (w - x) / X \rceil\)
      • 更新剩余水量:\(x = x + cnt \times X - w\)
      • 返回所需时间:\(w + cnt \times T\)(浇水时间 \(w\) + 加水时间 \(cnt \times T\)
    • 双指针模拟\(l = 1, r = n, tl = 0, tr = 0, wl = A, wr = B\)):
      • \(tl \leq tr\):皮皮先处理植物 \(l\)\(tl += water(wl, A, w[l++])\)
      • 否则:小美先处理植物 \(r\)\(tr += water(wr, B, w[r--])\)
    • 输出答案\(\max(tl, tr)\)
  4. 时间/空间复杂度

    • 时间复杂度:\(O(n)\),每株植物被处理一次
    • 空间复杂度:\(O(n)\),存储需水量数组
  5. 双指针的核心思想

    • 相向推进:皮皮和小美从两端向中间靠拢,用 \(l\)\(r\) 指针分别追踪
    • 贪心选择:每次让当前总时间较小的一方先行动,确保"先到先浇"的规则被满足,同时最小化总完成时间(类似流水线调度)
    • 加水次数计算:向上取整 \(\lceil (w - x) / X \rceil\) 确保水量足够浇灌当前植物,剩余水量留给下一株
    • 时间累积:各自独立累积时间,最终答案取两者最大值(最后完成的一方决定总时间)
    • 适用于双向并行处理、资源约束调度、相向双指针类问题

【算法标签】

双指针

【代码详解】

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 100005;
int n, A, B, T;  // n: 货物数量,A: 左机器人加水速度,B: 右机器人加水速度,T: 移动单位时间
int w[N];  // 货物重量数组
int water(int &x, int X, int w)  // 计算加水时间函数
{int cnt = ceil(1.0*(w-x)/X);  // 计算需要加水的次数x = x + cnt * X - w;  // 更新剩余水量return w + cnt * T;  // 返回所需时间
}
signed main()
{cin >> n >> A >> B >> T;  // 输入参数for (int i=1; i<=n; i++)  // 输入货物重量cin >> w[i];int l = 1, r = n, tl = 0, tr = 0, wl = A, wr = B;  // 初始化指针和时间while (l<=r)  // 双指针处理{if (tl <= tr)  // 如果左机器人总时间小于等于右机器人tl += water(wl, A, w[l++]);  // 左机器人处理货物else  // 否则tr += water(wr, B, w[r--]);  // 右机器人处理货物}cout << max(tl, tr) << endl;  // 输出最大时间return 0;
}

【运行结果】

5 1 9 5
7 3 2 3 2
37
← 返回列表