#P3310. 第2题-将军分配物资方案
-
1000ms
Tried: 1070
Accepted: 134
Difficulty: 4
所属公司 :
华为
时间 :2025年7月23日-暑期实习
-
算法标签>模拟
第2题-将军分配物资方案
题面描述
-
有一队粮食车队,每队运来K辆粮车;
-
有若干副将按序排队,每人需求若干辆粮车;
-
规则:
- 当前车队粮车数为K。
- 若K=当前副将需求,则该副将和车队同时出列。
- 若K>当前副将需求,设前i名副将总需求 Si=sumj=1irj. 找最大i使得 Si≤K<Si+1 则前i 名副将和车队同时出列。
- 若K<当前副将需求,则该副将移到队尾,车队保留在队首,继续本车队的领取尝试。
-
重复直到车队或副将任意一方耗尽,输出最终剩余未领到粮食的副将人数。
思路
- 准备两条队列,一条存储各县的粮车数,一条存储各副将的需求数。
- 每次取出队首的粮车数K,记录下要“看”副将队列的最大次数(即当前副将人数),防止无限循环。
- 在不超过这次数的尝试中,如果遇到第一位需求不超过K的副将,就开始连续为后续所有需求累计之和,直到总和超过K为止;被满足的副将全部出队,该车队也出队。
- 若某位副将需求大于K,就将其移到队尾,继续让同一车队尝试下一个副将;若尝试次数用尽仍无人匹配,则直接丢弃该车队。
- 重复上述过程,直到车队或副将队列为空,剩余副将数量即为未领到粮食的人数。
C++
#include <bits/stdc++.h>
using namespace std;
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
string line;
// 读取并校验两行输入
if(!getline(cin, line) || line.empty()){ cout << -1; return 0; }
istringstream sc(line);
vector<int> cars;
int x;
while(sc >> x){
if(x < 1 || x > 100){ cout << -1; return 0; }
cars.push_back(x);
}
if(!getline(cin, line) || line.empty()){ cout << -1; return 0; }
istringstream sg(line);
vector<int> req;
while(sg >> x){
if(x < 1 || x > 100){ cout << -1; return 0; }
req.push_back(x);
}
deque<int> carQ(cars.begin(), cars.end()), genQ(req.begin(), req.end());
// 模拟发放
while(!carQ.empty() && !genQ.empty()){
int K = carQ.front();
carQ.pop_front();
int attempts = genQ.size();
bool fed = false;
// 尝试最多“看”所有副将一次
while(attempts--){
if(genQ.front() <= K){
// 找到第一个需求 ≤ K 的副将,开始累计喂养
int sum = 0;
while(!genQ.empty() && sum + genQ.front() <= K){
sum += genQ.front();
genQ.pop_front();
}
fed = true;
break;
} else {
// 当前需求大于 K,移到队尾再试
int v = genQ.front(); genQ.pop_front();
genQ.push_back(v);
}
}
// 如果 attempts<0 且未 fed,则该车无人可喂,直接丢弃
}
// 剩余副将数即为未能领到粮食的数量
cout << genQ.size();
return 0;
}
Python
import sys
from collections import deque
def main():
data = sys.stdin.read().strip().splitlines()
if len(data) != 2:
print(-1); return
try:
cars = list(map(int, data[0].split()))
req = list(map(int, data[1].split()))
if any(x<1 or x>100 for x in cars+req):
print(-1); return
except:
print(-1); return
carQ = deque(cars)
genQ = deque(req)
while carQ and genQ:
K = carQ.popleft()
attempts = len(genQ)
fed = False
# 每辆车尝试“看”所有副将一次
for _ in range(attempts):
need = genQ[0]
if need <= K:
total = 0
# 累计喂到最大 i,使 sum ≤ K
while genQ and total + genQ[0] <= K:
total += genQ.popleft()
fed = True
break
else:
genQ.rotate(-1) # 当前副将移到队尾
# 若未 fed,则该车无人可喂,直接丢弃(不 re-enqueue)
# 输出剩余副将数
print(len(genQ))
if __name__ == "__main__":
main()
Java
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String l1 = br.readLine(), l2 = br.readLine();
if(l1 == null || l2 == null){ System.out.println(-1); return; }
Queue<Integer> carQ = new LinkedList<>(), genQ = new LinkedList<>();
try {
for(String s : l1.trim().split("\\s+")) {
int v = Integer.parseInt(s);
if(v<1 || v>100){ System.out.println(-1); return; }
carQ.offer(v);
}
for(String s : l2.trim().split("\\s+")) {
int v = Integer.parseInt(s);
if(v<1 || v>100){ System.out.println(-1); return; }
genQ.offer(v);
}
} catch(Exception e){
System.out.println(-1);
return;
}
while(!carQ.isEmpty() && !genQ.isEmpty()){
int K = carQ.poll();
int attempts = genQ.size();
boolean fed = false;
for(int i=0; i<attempts; i++){
int need = genQ.peek();
if(need <= K){
int sum = 0;
// 累计喂养前 i 名副将,使 sum ≤ K
while(!genQ.isEmpty() && sum + genQ.peek() <= K){
sum += genQ.poll();
}
fed = true;
break;
} else {
// 当前副将需求过大,移到队尾
genQ.offer(genQ.poll());
}
}
// 若始终未 fed,则车队丢弃
}
// 副将队列剩余大小即为未领取数量
System.out.println(genQ.size());
}
}
题目内容
古代战争时期,各县向前线战场运送粮食,各县提供的粮食车数不一样,到达前线后需排队进入军营,一次只能进入一个县车队,同时军营中的多个副将排队领取粮食,排在第 1 名的为 L1 ,第 2 名为 L2 ,以此类推。
将军制定了一套发放规则:
假设当前进入营寨的县车队运来的粮食车数为 K
1、若 K 等于当前副将的需求,则直接领走,县车队跟随副将一起离开队伍。继续下一轮】
2、若 K 大于当前副将 L1 的需求,则把后续营的需求纳入进来一起看,即找一个数字,使领取。前 i 个副将的总需求刚好小于等于 K ,但前 i+1 个副将的总需求大于 K 。此时将该县车队粮食全部分给这 i 个副将,然后下一个县车队进入军营,下一个副将(即编号 i+1 的副将)作为队首开始下一轮领取。
3、若 K 小于当前副将需求,则该营放弃本次领取,走到队尾重新排队。
问按照此规则发放,最终有多少个副将不能领导粮食?
输入描述
输入为两行:
第 1 行为各县粮车数的数组 cars ,空格分隔,car 表示编号 i(i<=1000) 的县运来的粮食车数 (1<=car[i]<=100)。例如: 3 5 7 9 3 2 1
第 2 行为各副将需求数组 generalRequires 数,空格分隔,generalRequires[j] 表示编号
j (j<=1000)的副将的需求数(1<=generalRequires[i]<=100)。
例如:1 2 4 5 2
非法输入返回 −1
输出描述
输出不能分到粮食的副将人数。
例如:
0 表示没有副将不能分到粮食
1 表示有 1 名副将不能够分到足够的粮食
2 表示有 2 名副将不能分到粮食,以此类推
样例1
输入
1
5 6
输出
2
说明
没有车数能够满足副将需求,所有副将均未能领到粮食,输出未领取粮食副将个数 2
样例2
输入
3 5 7 3 4
2 4 8 5 2
输出
1
说明
1、0 号车队(3 车粮食)被 0 号副将( 1 车需求)领走:
-
[3],5,7,3,4
-
[1],4,8,5,2
2、1 号车队被 1 号副将领走:
-
[3],[5],7,3,4
-
[1],[4],8,5,2
3、2 号车队( 7 车粮食)不能满足 2 号副将( 8 车需求),因此 2 号副将重新排队:
-
[3],[5],7,3,4
-
[1],[4],5,2,[8]
3、2 号车队( 7 车粮食)被下 2 个副将( 5+2 车需求)领走:
- [3],[5],[7],3,4
4、8 车需求的副将始终领不到粮食,因此输出副将个数为 1
样例3
输入
3 5 7 9 3 2 1
1 2 4 5 2
输出
0
说明
1、0 号车队被 0、1 号副将领走:
-
[3],5,7,9,3,2,1
-
[1,2],4,5,2
2、1 号车队被 2 号副将领走:
-
[3],[5],7,9,3,2,1
-
[1,2],[4],5,2
3、2 号车队被 3、4 号副将领走:
[3],[5],[7],9,3,2,1
4、所有副将都领取到了粮食,返回结果 0