【蓝桥省赛倒计时】B组Java冲刺打卡(三)

目录

一、打水问题

二、夺宝奇兵

三、调手表

四、一步之遥


一、打水问题

题目描述

N个人要打水,有M个水龙头,第i个人打水所需时间为Ti,请安排一个合理的方案使得所有人的等待时间之和尽量小。

提示
一种最佳打水方案是,将N个人按照Ti从小到大的顺序依次分配到M个龙头打水。
例如样例中,Ti从小到大排序为1,2,3,4,5,6,7,将他们依次分配到3个龙头,则去龙头一打水的为1,4,7;去龙头二打水的为2,5;去第三个龙头打水的为3,6。
第一个龙头打水的人总等待时间  =  0  +  1  +  (1  +  4)  =  6
第二个龙头打水的人总等待时间  =  0  +  2  =  2
第三个龙头打水的人总等待时间  =  0  +  3  =  3
所以总的等待时间  =  6  +  2  +  3  =  11

输入

第一行两个正整数N  M  接下来一行N个正整数Ti。 
N,M< =1000,Ti< =1000 

输出

最小的等待时间之和。(不需要输出具体的安排方案) 

样例输入

7 3
3 6 1 4 2 5 7

样例输出

11

        对题目理解很重要!这个题其实就是将打水人的时间做个排序,在分别安排到水龙头就行了。就是一种贪心的思想,对于最后被安排(水龙头个数)的M个人,是不用加入计算的(题目中只让求等待时间),其余看代码中解析。

import java.util.*;
public class Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n=sc.nextInt();
		int m=sc.nextInt();
		int[] arr=new int[n];
		for(int i=0;i<n;i++) {
			arr[i]=sc.nextInt();
		}
		Arrays.sort(arr);
		int[] num=new int[m];
		int sum=0;
		int j=0;
		while (j<n-m){ //最后一个人后面没人等待了 所以每个水龙头的最后一个人的时间都不用去加      
            for (int i = 0; i < m&&j<n-m; i++,j++) {    // j为打水的人
                temp[i]+=a[j];//第二个人打水人等待的时间为第一个打水人的打水时间 
                sum+=temp[i]; //第n个人等待的打水时间为前面n-1个人的打水时间和                
            }
        }
		System.out.println(sum);
	}
}

二、夺宝奇兵

题目描述

在一座山上,有很多很多珠宝,它们散落在山底通往山顶的每条道路上,不同道路上的珠宝的数目也各不相同.下图为一张藏宝地图:

7
3  8
8  1  0
2  7  4  4
4  5  2  6  5

”夺宝奇兵”从山下出发,到达山顶,如何选路才能得到最多的珠宝呢?在上图所示例子中,按照5-> 7-> 8-> 3-> 7的顺序,将得到最大值30

输入

第一行正整数N(100> =N> 1),表示山的高度 
接下来有N行非负整数,第i行有i个整数(1< =i< =N),表示山的第i层上从左到右每条路上的珠宝数目 

输出

一个整数,表示从山底到山顶的所能得到的珠宝的最大数目. 

样例输入

5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5

样例输出

30

        这个题是一个dp问题,对于dp问题,我们最主要的是要了解这个过程,题目中的山其实并不是直角三角形的,而是像“杨辉三角”那样的,代码如下:

import java.util.*;
public class Main{
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		 Scanner sc = new Scanner(System.in);
	        int n = sc.nextInt();
	        int[][] dp = new int[n][n];
	        for (int i = 0; i < n; i++) {
	            for (int j = 0; j <= i; j++) {
	                dp[i][j] = sc.nextInt();
	            }
	        }
	        for (int i = n-2; i >= 0; i--) {
	            for (int j = 0; j <= i; j++) {
	                dp[i][j] += Math.max(dp[i+1][j],dp[i+1][j+1]);
	            }
	        }
	        System.out.println(dp[0][0]);
	}
}

三、调手表

【题目】小明买了块高端大气上档次的电子手表,他正准备调时间呢。

在 M78 星云,时间的计量单位和地球上不同,M78 星云的一个小时有 n 分钟。

大家都知道,手表只有一个按钮可以把当前的数加一。在调分钟的时候,如果当前显示的数是 0 ,那么按一下按钮就会变成 1,再按一次变成 2 。如果当前的数是 n−1,按一次后会变成 0。

作为强迫症患者,小明一定要把手表的时间调对。如果手表上的时间比当前时间多 1,则要按 n - 1 次加一按钮才能调回正确时间。

小明想,如果手表可以再添加一个按钮,表示把当前的数加 k 该多好啊......

他想知道,如果有了这个 +k 按钮,按照最优策略按键,从任意一个分钟数调到另外任意一个分钟数最多要按多少次。

注意,按 +k按钮时,如果加 k 后数字超过 n-1,则会对 n 取模。

比如,n=10, k=6 的时候,假设当前时间是 0,连按 2 次 +k 按钮,则调为 2。

输入描述

一行两个整数 n(意义如题)。

输出描述

输出一行一个整数,表示按照最优策略按键,从一个时间调到另一个时间最多要按多少次。

        在这个题中,如果想达到题目最终的结果,有两种情况:第一种,直接通过+k就能达到需求时间,第二种,如果无法只用+k实现,那么实现时间的上一步绝对是+1【且+1的数量一定小于k】,代码如下:

import java.util.*;
public class Main{
	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];
        for (int i=1;i<n;i++){
            if (i%k==0){
                arr[i]=i/k;
            }else{
                arr[i]=arr[i-1]+1;
                for ( int j = 1; j <= arr[i-1]+1 ; j++ ) {
                    if ( ( k * j ) % n == i ) {
                        arr[i] = j;
                        break;
                    }
                }
            }
        }
        Arrays.sort(arr);
        System.out.println(arr[n-1]);
	}
}

四、一步之遥

【题目】从昏迷中醒来,小明发现自己被关在 X 星球的废矿车里。 矿车停在平直的废弃的轨道上。 他的面前是两个按钮,分别写着 “F” 和 “B” 。

小明突然记起来,这两个按钮可以控制矿车在轨道上前进和后退。 按 F,会前进 97 米。按 B 会后退127 米。 透过昏暗的灯光,小明看到自己前方 1 米远正好有个监控探头。 他必须设法使得矿车正好停在摄像头的下方,才有机会争取同伴的援助。 或许,通过多次操作 F 和 B 可以办到。

矿车上的动力已经不太足,黄色的警示灯在默默闪烁... 每次进行 F 或 B 操作都会消耗一定的能量。 小明飞快地计算,至少要多少次操作,才能把矿车准确地停在前方 1 米远的地方。

请问为了达成目标,最少需要操作的次数是多少。

        这个题也是理解题,只要理解题目就很简单了,我们可以假设现在位置为0,然后进行加减完成位置变成1,这样就可以实现了,代码如下:

public class Main{
	public static void main(String[] args) {
		System.out.println(ans(0));
	}
	private static int ans(int n) {
		int sum=0;
		for(int i=0;i<1000;i++) {
			for(int j=0;j<1000;j++) {
				if(sum+97*i-127*j==1) {
					return i+j;
				}
			}
		}
		return sum;	
	}
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

祁十一

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值