4 条题解
-
0
#include <bits/stdc++.h> using namespace std; int main(){ int n,m; cin>>n>>m; // int t[m]={0};//潜在风险:不建议用变量作为数组的长度 // int w[n]={0};//潜在风险:不建议用变量作为数组的长度 int t[101]={0}; int w[10001]={0}; for(int i=0;i<n;i++){ cin>>w[i]; } //开始第一批m个人接水 for(int j=0;j<m;j++){ t[j]=w[j]; } //循环条件:下一个接水的人去找位置接水 for(int k=m;k<n;k++){//注意下标从m开始,因为前面m个是0~m-1 //准备接水,要找那个水龙头是时间最小的 int mint=INT_MAX; int minidx=0; for(int i=0;i<m;i++){ if(t[i]<mint){ minidx=i; mint=t[i];//不要写成w[i] 所以数组变量名写成time[i]更不容易出错 } } //找到最小的水龙头位置了minidx t[minidx]+=w[k];//去接水,更新时间 } //全部人都接完了,找最大的水龙头时间 int maxt=0; for(int i=0;i<m;i++){ if(t[i]>maxt){ maxt=t[i]; } } cout<<maxt<<endl; } -
0
P1190 这道题(NOIP 2010 普及组 T2)是一道非常经典的模拟题,同时包含了一点点贪心的思想。题目描述得很长,但其实核心逻辑就像我们在超市排队结账一样。
为了帮助你独立解出这道题,我为你提供以下几个核心思路提示:
1. 核心模型:水龙头数组
想象一下,你有 个水龙头。我们可以用一个长度为 的数组(比如叫
time[m])来维护每一个水龙头当前还需要工作多长时间,或者理解为每一个水龙头将在第几秒结束当前任务。- 初始状态:前 个同学一来就占满了 个龙头。所以,数组的初始值就是前 个同学的接水量。
2. 关键逻辑:谁最先接完?
当第 个同学(也就是排队等待的第一位)准备去接水时,他会去哪一个龙头呢?
- 必然是去目前最快空闲下来的那个龙头!
- 怎么找? 你需要在
time数组里找到一个最小值。假设第 号龙头的时间最少,说明它最先空出来。
3. 状态更新:接力
当第 号龙头空出来后,排队的这位同学立刻补上去。
- 这对
time[k]会产生什么变化? - 原本的时间加上新同学需要的时间,就是这个龙头下一次空闲的时间。
- 公式:
time[min_index] += w[next_student]。
4. 循环处理
你只需要写一个循环,从第 个同学开始,直到第 个同学:
- 找到当前 个龙头中数值最小的那个(也就是最早结束的)。
- 把当前同学的接水量加到那个龙头的数值上。
5. 最终答案:什么时候全部结束?
当所有 个同学都安排好之后,
time数组里记录了每个龙头最终结束的时间。- 整个接水过程结束,必须等到最慢的那个龙头停下来。
- 所以,答案是
time数组里的最大值。
6. 数据范围提示
- ,。
- 这意味着你每次找最小值的操作(遍历 次)完全可以直接写循环找,不需要用堆(优先队列)等高级数据结构,暴力找最小值的总复杂度大约是 ,也就是 级别,计算机一眨眼就跑完了。
总结代码框架:
1. 读入 n, m 2. 读入所有人的接水量 w[] 3. 定义一个数组 s[] 用来存储 m 个龙头的累计时间 4. 先把前 m 个人的时间填入 s[] 5. 从第 m+1 个人开始循环到第 n 个人: a. 遍历 s[] 找到最小值的下标 min_idx b. s[min_idx] += 当前这个人的时间 6. 遍历 s[] 找到最大值,输出按照这个逻辑去写,代码会非常短且清晰。加油!
这个版本的答案有什么错
#include <bits/stdc++.h> using namespace std; int main(){ int n,m; cin>>n>>m; int t[m]={0}; int w[n]={0}; for(int i=0;i<n;i++){ cin>>w[i]; } //开始第一批m个人接水 for(int j=0;j<m;j++){ t[j]=w[j]; } //循环条件:下一个接水的人去找位置接水 for(int k=m+1;k<n;k++){ //准备接水,要找那个水龙头是时间最小的 int mint=INT_MAX; int minidx=0; for(int i=0;i<m;i++){ if(t[i]<mint){ minidx=i; mint=w[i]; } } //找到最小的水龙头位置了minidx t[minidx]+=w[k];//去接水,更新时间 } //全部人都接完了,找最大的水龙头时间 int maxt=0; for(int i=0;i<m;i++){ if(t[i]>maxt){ maxt=t[i]; } } cout<<maxt<<endl; }同学,你写得很接近了!但是你的程序里有两个非常严重的逻辑错误,这会导致答案完全不对。
我们来看看问题出在哪里:
1. 致命错误:更新最小值时的赋值错了
请看这段代码:
if(t[i] < mint){ minidx = i; mint = w[i]; // <--- 错误在这里!!! }原因分析:
t[i]代表第i号水龙头当前累计的时间。mint是用来记录“当前所有水龙头里最小的时间”。- 当你发现
t[i]更小时,应该把t[i]的值赋给mint。 - 你写成了
mint = w[i]。注意:i是水龙头的编号(0到m-1),而w是存人的接水量的数组。w[i]只是第i个人的接水量,并不是这个水龙头累计的时间!
修正:
mint = t[i]; // 应该是把这个水龙头的时间赋给 mint2. 致命错误:漏掉了第 m 个人(下标错误)
请看循环的起始条件:
for(int k = m + 1; k < n; k++) // <--- 错误在这里原因分析:
- 数组下标是从
0开始的。 - 前
m个人占用了w[0]到w[m-1]。 - 下一个要接水的人,下标应该是
m。 - 你写的是
k = m + 1,这意味着你直接跳过了下标为m的那个人(也就是第m+1个人),让他“人间蒸发”了。
修正:
for(int k = m; k < n; k++) // 从第 m 个下标开始3. 潜在风险:变长数组 (VLA)
int t[m]={0}; int w[n]={0};在标准的 C++ 中,不能用变量来定义数组长度(虽然有些编译器支持,但在比赛中很不安全,容易爆零或编译错误)。 建议:根据题目数据范围()定义固定大小的全局数组,或者大一点的局部数组。
修改后的正确代码
#include <bits/stdc++.h> using namespace std; int main(){ int n, m; cin >> n >> m; // 建议开固定大小的数组,防止编译器报错 // 题目范围 n<=10000, m<=100 int w[10005]; int t[105] = {0}; // 水龙头数组初始化为0 for(int i = 0; i < n; i++){ cin >> w[i]; } // 1. 第一批 m 个人先把水龙头占满 for(int j = 0; j < m; j++){ t[j] = w[j]; } // 2. 剩下的人(下标从 m 开始)找空位 // 修正点1:k 从 m 开始,不是 m+1 for(int k = m; k < n; k++){ // 找当前哪个水龙头时间最短 int mint = INT_MAX; int minidx = 0; for(int i = 0; i < m; i++){ if(t[i] < mint){ minidx = i; mint = t[i]; // 修正点2:这里必须是 t[i],不是 w[i] } } // 让这个人去最快空闲的水龙头接水 t[minidx] += w[k]; } // 3. 找最大的时间作为结束时间 int maxt = 0; for(int i = 0; i < m; i++){ if(t[i] > maxt){ maxt = t[i]; } } cout << maxt << endl; return 0; }把这两个地方改过来,你的逻辑就完全通了!快去试试吧。
-
0
#include <bits/stdc++.h> using namespace std; int main(){ int n,m; cin>>n>>m; // int t[m]={0};//潜在风险:不建议用变量作为数组的长度 // int w[n]={0};//潜在风险:不建议用变量作为数组的长度 int t[101]={0}; int w[10001]={0}; … } //全部人都接完了,找最大的水龙头时间 int maxt=0; for(int i=0;i<m;i++){ if(t[i]>maxt){ maxt=t[i]; } } cout<<maxt<<endl; } -
0
C++ :
#include<iostream> using namespace std; int T[200]; int main() { int n,m,t; cin >> n >> m; for(int i=0; i<n; ++i) { cin >> t; int min_index = 0; for(int j=1; j<m; ++j) { if(T[j] < T[min_index]) min_index = j; } T[min_index] += t; } int max_index = 0; for(int i=1; i<m; ++i) { if(T[i] > T[max_index]) max_index = i; } cout << T[max_index] << endl; return 0; }Pascal :
var a:array[1..11000] of integer; b:array[1..100] of integer; i,j,n,m,next,sum:longint; function check:boolean; var i:integer; begin for i:=1 to m do if a[b[i]]>0 then exit(true); check:=false; end; begin readln(n,m); for i:=1 to n do read(a[i]); for i:=1 to m do b[i]:=i; next:=m+1; repeat for i:=1 to m do begin dec(a[b[i]]); if a[b[i]]=0 then begin b[i]:=next; inc(next); end; end; inc(sum); until not check; writeln(sum); end.
- 1
信息
- ID
- 752
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者