一起是三个编程题,总共80分。
昨天笔试完,顺便记载下。
第一题:
- 零件组装
- 小明管理了一家工厂。该工厂生产一种大型机械,需要由四种零件组装完成。我们不妨称这四种零件为A,B,C,D。
- 由于生产机械需要保证产品的质量,工厂对每个零件会进行检测,量化出每个零件的评分。评分当然有一个合格的分数(我们不妨假设它是x),当零件评分大于x的时候,该零件才是合格的。
- 四个分别合格的零件A,B,C,D可以组装成一个合格的大型机械。现在小明想知道当前产出的这些零件一共可以组装成多少合格的大型机械?
- 请注意:每个零件至多只能用于一个大型机械的组装,不能反复组装。
思路:记录每种零件合格的个数,四个零件才能凑一套,所以只能凑合格的四个零件数量中最小的套数。
Scanner sc = new Scanner(System.in);
//1.获取输入
int aNum = sc.nextInt();
int bNum = sc.nextInt();
int cNum = sc.nextInt();
int dNum = sc.nextInt();
int score = sc.nextInt();
//2.记载合格数量
int a = 0,b = 0,c =0,d = 0;
//3.合格的零件
for(int i = 0;i<aNum;i++){
int tep = sc.nextInt();
if(tep>score){
a++;
}
}
//顺便记载最小套数
int min = a;
for(int i = 0;i<bNum;i++){
int tep = sc.nextInt();
if(tep>score){
b++;
}
}
min = Math.min(min,b);
for(int i = 0;i<cNum;i++){
int tep = sc.nextInt();
if(tep>score){
c++;
}
}
min = Math.min(min,c);
for(int i = 0;i<dNum;i++){
int tep = sc.nextInt();
if(tep>score){
d++;
}
}
min = Math.min(min,d);
System.out.println(min);
第二题:
- 最佳传送方案:
- 现在你位于连绵的峰峦之间。你的任务是从1号山峰抵达n号山峰。
- 你拥有一个传送门可以将你送往后续距离不超过k的山峰中。举例,当k=2时,若你在山峰1,则你可以传送至山峰2或山峰3。这里距离的定义为编号的差值。
- 使用传送门需要付出金币。付出的规则如下:若当前在山峰u,将要去往的是山峰v,当山峰u的高度高于山峰v时,不需要付出金币;否则,当山峰u的高度低于山峰v时,需要付出(山峰v的高度 - 山峰u的高度)这么多的金币。
- 举例如下:
- 当前在山峰1,高度为5,若传送至山峰2,高度为4,因为5>4,本次不花费金币;
- 当前在山峰1,高度为5,若传送至山峰3,高度为6,因为6>5,本次花费(6-5=1)的金币。
- 你的任务是从1号山峰恰好传送至n号山峰,询问你最少要花费的金币数量。
思路:明显动态规划,dp[i]为能够到的起跳点中最小的dp[j]+从起跳点到第i个山峰花的金币之和中的最小值。
Scanner sc = new Scanner(System.in);
//山峰数量
int n = sc.nextInt();
//每次传送的距离
int dis = sc.nextInt();
//数组接山峰的高度
int[] high = new int[n];
int count = 0;
while(count!=n){
high[count++] = sc.nextInt();
}
//动态规划:
//dp[i] : 到达第i个山峰的所需要的最小金币数
//dp[i] = Math.min (dp[0...i-1]+金币数)
int[] dp = new int[n];
dp[0] = 0; //本来就在第一个山峰
for(int i = 1;i<n;i++){
//能够到的起跳点
int tep = i-dis>=0? i-dis : 0;
//记载dp[i]的所有起跳点到第i个山峰的金币最小值,每个起跳点中符合条件就更新
int min = Integer.MAX_VALUE;
for(int j = tep;j>=0&&j<i;j++){
//从第一座山峰到起跳点j再到i花的金币
int minTep = 0;
if(high[j]>=high[i]){
//之前的跳点比第i座山峰高:免费
minTep = dp[j];
}else{
//比第i座山峰低:要交钱
minTep = dp[j]+high[i]-high[j];
}
min = Math.min(min,minTep);
//注意这里的情况,这里考虑不周只能a一半
if(dp[i]==0){
//i的第一个起跳点一定要有值,不然会一直是0
dp[i] =min;
}
else{
//不是i的第一个起跳点,及时更新最小值
dp[i] = Math.min(dp[i],minTep);
}
}
}
System.out.println(dp[n-1]);
第三题:
没a出来,题目也来不及记载了。
记忆里是给了个数组,还给了个k,问数组的子区间是否被支配,输出这个数组被支配的区间个数。
被支配就是这个元素是区间的众数,而且这个元素的数量要至少>=k。
暴力肯定超时,时间要求是3000ms(java),暴力出来3400多ms。
写的代码如下,a了34%
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int k = sc.nextInt();
int[] arr = new int[n];
int count = 0;
while(count!=n){
arr[count++] = sc.nextInt();
}
int res = 0;
//把连续子数组往下传,返回是否被支配
for(int i = 0;i<n;i++){
for(int j = i+2;j<n;j++){
if(isMatched(arr,i,j,k)){
res++;
}else {
continue;
}
}
}
System.out.println(res);
}
public static boolean isMatched(int[] arr,int left,int right,int k){
Map<Integer,Integer> map = new HashMap<>();
//众数的数量
int maxCount = 0;
for(int i = left;i<=right;i++){
map.put(arr[i],map.getOrDefault(arr[i],0)+1);
maxCount = Math.max(maxCount,map.get(arr[i]));
}
for(int i = left;i<=right;i++){
int tep = map.get(arr[i]);
if(tep>=k && tep==maxCount){
return true;
}
}
return false;
}
看还有没有改进方法,我写出来了再来改。