From 88a485281235b0c60e2bae37f3cf2ee2654f4bc2 Mon Sep 17 00:00:00 2001 From: HuangHai <10402852@qq.com> Date: Sun, 5 Oct 2025 19:16:56 +0800 Subject: [PATCH] 'commit' --- TangDou/CSP-J/AcWingTraining/T1/442.md | 198 ++++++++++++---------- TangDou/CSP-J/AcWingTraining/T1/442_2.cpp | 2 + TangDou/CSP-J/AcWingTraining/T1/442_3.cpp | 30 ++++ 3 files changed, 139 insertions(+), 91 deletions(-) create mode 100644 TangDou/CSP-J/AcWingTraining/T1/442_3.cpp diff --git a/TangDou/CSP-J/AcWingTraining/T1/442.md b/TangDou/CSP-J/AcWingTraining/T1/442.md index 6da6cf1..e7b54b3 100644 --- a/TangDou/CSP-J/AcWingTraining/T1/442.md +++ b/TangDou/CSP-J/AcWingTraining/T1/442.md @@ -1,7 +1,113 @@ ## 排队接水 -### 一、数学证明 + +### 一、原题 +https://www.luogu.com.cn/problem/P1190 + +P1190 [NOIP 2010 普及组] 接水问题 + +```cpp {.line-numbers} +#include +using namespace std; +const int MAX_N = 10010; // 最大人数 +const int MAX_M = 110; // 最大水龙头数 +int n, m; // n: 同学人数, m: 水龙头数量 +int w[MAX_N]; // 每位同学的接水量 +int taps[MAX_M]; // 每个水龙头的当前结束时间 +int main() { + cin >> n >> m; + + // 模拟接水过程 + for (int i = 0; i < n; i++) { + cin >> w[i]; + + // 找到最先结束的水龙头 + int min_tap = 0; + for (int j = 1; j < m; j++) + if (taps[j] < taps[min_tap]) + min_tap = j; + // 将i号同学的接水量分配给最先结束的水龙头 + taps[min_tap] += w[i]; + } + // 找到所有水龙头中最大的结束时间 + int result = 0; + for (int i = 0; i < m; i++) + result = max(result, taps[i]); + + cout << result << endl; + return 0; +} +``` + +### 三、变形1 +https://www.acwing.com/problem/content/description/444/ + +```cpp {.line-numbers} +#include + +using namespace std; +const int N = 10010, M = 200; +int n, m; +int w[N]; +int q[M]; + +int main() { + cin >> n >> m; + for (int i = 0; i < n; i++) cin >> w[i]; + + for (int i = 0; i < n; i++) { + int t = 0; + for (int j = 0; j < m; j++) { + if (q[j] < q[t]) + t = j; + } + q[t] += w[i]; + } + int res = 0; + for (int i = 0; i < m;i++) res = max(res, q[i]); + cout << res << endl; + return 0; +} +``` +### 二、变形2【一个水龙头前排队接水】 +https://www.acwing.com/problem/content/description/5945/ + +```cpp {.line-numbers} +#include +using namespace std; +const int N = 1005; + +struct Node { + int num; + int sum; +} a[N]; +bool cmp(Node x, Node y) { + if (x.sum == y.sum) + return x.num < y.num; + return x.sum < y.sum; +} +int main() { + int n; + cin >> n; + for (int i = 0; i < n; i++) { + cin >> a[i].sum; + a[i].num = i + 1; + } + sort(a, a + n, cmp); + double temp = 0.00; + for (int i = 0; i < n; i++) { + cout << a[i].num << " "; + temp += (n - (i + 1)) * a[i].sum; + } + cout << endl; + printf("%.2f", temp / n * 1.00); + return 0; +} +``` + + +### 四、数学证明 首先我们要排的是所有的元素,但是为什么是从小到大呢??? 排队总是象征要排序,每个元素在此序列下都要满足条件,也就是从中拿出两个相邻元素同样满足条件: @@ -23,93 +129,3 @@ $a_i$ 于是得出结论:**当$a_i$在$b_i$前面时,时间为最小值**。 于是反推回总体,两两相较,那么越小的应该越排在前面,以至于总时间越小。 - -### 二、代码 -```cpp {.line-numbers} -#include - -using namespace std; -const int N = 10010, M = 200; -int n, m; -int w[N]; -int q[M]; - -int main() { - cin >> n >> m; - for (int i = 0; i < n; i++) - cin >> w[i]; - - for (int i = 0; i < n; i++) { - // 找出最小值 - int t = 0; - for (int j = 0; j < m; j++) { - if (q[j] < q[t]) - t = j; - } - // 将i号同学安排到第t个位置上 - q[t] += w[i]; - } - int res = 0; - for (int i = 0; i < m; i++) - res = max(res, q[i]); // 找出最大值就是答案 - cout << res << endl; - return 0; -} -``` - -### 三、变形 - -**【题目描述】** -有$n$个人在一个水龙头前排队接水,假如每个人接水的时间为$T_i$,请编程找出这$n$个人排队的一种顺序,使得$n$个人的平均等待时间最小。 - -**【输入】** -共两行,第一行为$n(1≤n≤1000)$;第二行分别表示第$1$个人到第$n$个人每人的接水时间$T_1,T_2,…,T_n$,每个数据之间有$1$个空格。 - -**【输出】** -有两行,第一行为一种排队顺序,即$1$到$n$的一种排列;第二行为这种排列方案下的平均等待时间(输出结果精确到小数点后两位)。 - -**【输入样例】** -``` -10 -56 12 1 99 1000 234 33 55 99 812 -``` -**【输出样例】** -``` -3 2 7 8 1 4 9 6 10 5 -291.90 -``` - -``` -http://ybt.ssoier.cn:8088/problem_show.php?pid=1319 -``` - -```cpp {.line-numbers} -#include -using namespace std; -const int N = 1005; - -struct Node { - int num; - int sum; -} a[N]; -bool cmp(Node x, Node y) { - return x.sum < y.sum; -} -int main() { - int n; - cin >> n; - for (int i = 0; i < n; i++) { - cin >> a[i].sum; - a[i].num = i + 1; - } - sort(a, a + n, cmp); - double temp = 0.00; - for (int i = 0; i < n; i++) { - cout << a[i].num << " "; - temp += (n - (i + 1)) * a[i].sum; - } - cout << endl; - printf("%.2f", temp / n * 1.00); - return 0; -} -``` \ No newline at end of file diff --git a/TangDou/CSP-J/AcWingTraining/T1/442_2.cpp b/TangDou/CSP-J/AcWingTraining/T1/442_2.cpp index 208163c..e6229d0 100644 --- a/TangDou/CSP-J/AcWingTraining/T1/442_2.cpp +++ b/TangDou/CSP-J/AcWingTraining/T1/442_2.cpp @@ -7,6 +7,8 @@ struct Node { int sum; } a[N]; bool cmp(Node x, Node y) { + if (x.sum == y.sum) + return x.num < y.num; return x.sum < y.sum; } int main() { diff --git a/TangDou/CSP-J/AcWingTraining/T1/442_3.cpp b/TangDou/CSP-J/AcWingTraining/T1/442_3.cpp new file mode 100644 index 0000000..94bf9b4 --- /dev/null +++ b/TangDou/CSP-J/AcWingTraining/T1/442_3.cpp @@ -0,0 +1,30 @@ +#include +using namespace std; +const int MAX_N = 10010; // 最大人数 +const int MAX_M = 110; // 最大水龙头数 +int n, m; // n: 同学人数, m: 水龙头数量 +int w[MAX_N]; // 每位同学的接水量 +int taps[MAX_M]; // 每个水龙头的当前结束时间 +int main() { + cin >> n >> m; + + // 模拟接水过程 + for (int i = 0; i < n; i++) { + cin >> w[i]; + + // 找到最先结束的水龙头 + int min_tap = 0; + for (int j = 1; j < m; j++) + if (taps[j] < taps[min_tap]) + min_tap = j; + // 将i号同学的接水量分配给最先结束的水龙头 + taps[min_tap] += w[i]; + } + // 找到所有水龙头中最大的结束时间 + int result = 0; + for (int i = 0; i < m; i++) + result = max(result, taps[i]); + + cout << result << endl; + return 0; +} \ No newline at end of file