#P3310. 第2题-将军分配物资方案
          
                        
                                    
                      
        
              - 
          
          
                      1000ms
            
          
                      Tried: 1061
            Accepted: 132
            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