纯职业士兵
问题描述
在蓝桥王国,国王统治着一支由 nn 个小队组成的强大军队。每个小队都由相同职业的士兵组成。具体地,第 ii 个小队包含了 bibi 名职业为 aiai 的士兵。
近日,国王计划在王宫广场举行一场盛大的士兵检阅仪式,以庆祝王国的繁荣昌盛。然而,在士兵们入场的过程中,一场突如其来的风暴打乱了他们的行列,使得不同小队的士兵混杂在一起,次序乱成一团,
尽管国王无法知道每个士兵的具体职业,但为了确保仪式能顺利进行,国王打算从这些混乱的士兵中选出一部分,组成 kk 个“纯职业小组”进行检阅。一个“纯职业小组”定义为由 33 名同职业的士兵组成的队伍。
请问,国王至少需要选择多少名士兵,才能确保这些士兵可以组成 kk 个“纯职业小组”。
输入格式
输入包含多组数据。
第一行包含一个整数 TT,表示有 TT 组数据。
对于每组数据:
- 第一行包含两个整数 ntnt 和 kk,表示小队的数量和要组成的纯职业小组的数量。
- 接下来的 ntnt 行,每行包含两个整数 aiai 和 bibi,表示第 ii 个小队中士兵的职业和数量。
输出格式
对于每组数据,输出一个整数,表示为了组成 kk 个“纯职业小组”,国王至少需要选择的士兵数量。如果无论如何也无法组成 kk 个“纯职业小组”,则输出 −1−1。
思路1:
首先考虑什么情况下输出-1;有两种思考:一个是最初每个队士兵个数小于3的组数数量少于k个。还有一种是军队所有士兵的数量总和小于3*k(就像给的样例2)。
难点在于想找到至少多少名士兵?先给出多组样例,试试找规律。样例1有三组队伍,每个队伍三人,所以可以化简为aaa,bbb,ccc三组,极端抽取情况就是abcabcab,所以至少需要8人。
根据极端情况,对样例修改,若三个队伍人员数量分别为二,四,三。可以化简为aa,bbbb,ccc,则极端情况是abcabcbc,也是选8人。
以此类推,试着写出代码。
题解思路
问至少要挑选多少名士兵,且k组里面每个组都是3人,则需要考虑若有一个组是9人,则可以分为三组,因此先统计出所有组数(在原有基础上分割)。
具体代码
1)Map <Integer, Long> h; Long表示包装类而不是基本数据类型
2)h = new HashMap<>() ;
3)h.put(a, h.getOrDefault(a , 0L) + b) ; getOrDefault表示如果存在键a,返回其对应的数值并+b, 若不存在就是0+b,也就是b
4)List<Long> b = new ArrayList<> (h.values()); 将h里面的值提取出来放在集合b中。
思路
继续:
不考虑选取士兵的顺序,极端情况就是每一种类型都选了两个人或者更少(取决于此类型士兵的数量),一直凑不齐第三个,用used记录选过的人数,再将b里面的数量减去
代码
long used = Math.min(b.get(i), 2); 因为可能b里面的人数不足两个人
b.set(i, b.get(i)-used);
import java.util.*;
// 1:无需package
// 2: 类名必须Main, 不可修改
public class Main
public static void main(String args[])
Scanner scan = new Scanner(System.in);
//在此输入您的代码...
int t = scan.nextInt();
for(int j = 0; j < t; j ++ ){
int n;
long k;
n = scan.nextInt();
k = scan.nextLong();
Map<Integer, Long> h = new HashMap<> ();
for(int i = 0;i < n; i ++ ){
int a = scan.nextInt();
long b = scan.nextLong();
h.put(a, h.getOrDefault(a, 0L) + b);
}
List<Long> b = new ArrayList<> (h.values());
long cnt = 0, res = 0;
for(int i = 0; i < b.size(); i ++ ){
long full = b.get(i)/3;
cnt += full;
long used = Math.min(b.get(i), 2);
b.set(i, b.get(i)-used);
res += used;
}
}
思路
需要考虑输出为-1
当所有人数除以三的个数都小于k组,表明无法集齐
如果有输出,统计b集合里每个数可以分成几组,计算出余数
if(cnt < k) {
System.out.println(-1);
}
else {
long c1 = 0, c2 = 0, c3 = 0;
for(long x : b) {
c3 += x/3;
x %= 3;
if(x == 1) c1++;
else if(x == 2) c2 ++;
}
思路
!!!这里我不明白为什么先k--; res++;
最后一部分代码还是有点乱,需要再想清楚
k--;
res++;
long v = Math.min(k, c3);
k-=v;
c3-=v;
res += v*3;
v = Math.min(k, c2);
k-=v;
c2-= v;
res += v*2;
v = Math.min(k, c1);
k-=v;
c1-=v;
res+=v;
System.out.println(res);
}
}
scan.close();
}
}