题目描述:
在系统、网络均正常的情况下组织核酸采样员和志愿者对人群进行核酸检测筛查。每名采样员的效率不同,采样效率为N人/小时。由于外界变化,采样员的效率会以M人/小时为粒度发生变化,M为采样效率浮动粒度,M=N10%,输入保证N10%的结果为整数。采样员效率浮动规则:采样员需要一名志愿者协助组织才能发挥正常效率,在此基础上,每增加一名志愿者,效率提升1M,最多提升3M;如果没有志愿者协助组织,效率下降2M。
怎么安排速度最快?求总最快检测效率(总检查效率为各采样人员效率值相加)。
输入描述:
第一行:第一个值,采样员人数,取值范围[1,100];第二个值,志愿者人数,取值范围[1,500];
第二行:各采样员基准效率值(单位人/小时),取值范围[60,600],保证序列中每项值计算10%为整数
输出描述:
第一行:总最快检测效率(单位人/小时)
补充说明:
输入需要保证采样员基准效率值序列的每个值*10%为整数
示例
输入:
2 2
200 200
输出:
400
题目解析
解题思路
求最优解,可以考虑使用动态规划的方式实现。而动态规划主要是设置状态转移方程。
状态转移方程思路:
每次新增加一个医生,需要考虑给他配置几个志愿者【0,1,2,3】才能最优
dp[M:医生数][N:志愿者数量] 【注意: dp[M-1]的所有状态已经得到最优解了 】
- 如果不分配志愿者,则=dp[M-1][N] + 该医生效率减少20%
- 如果分配1个志愿者,则=Max(不分配志愿者,dp[M-1][N-1]+该医生效率)
- 如果分配2个志愿者,则=Max(分配1个志愿者,dp[M-1][N-2]+该医生效率+提升2倍效率)
- 如果分配3个志愿者,则=Max(分配2个志愿者,dp[M-1][N-3]+该医生效率+提升3倍效率)
注意:以上需要按顺序比较
java代码实现
package com.HW;
import javax.net.ssl.HandshakeCompletedListener;
import java.util.Arrays;
import java.util.Collections;
/**
* @ClassName : TNucleicAcidTesting
* @Author : kele
* @Date: 2023/10/22 14:42
* @Description : 核酸检测人员安排
*/
public class TNucleicAcidTesting {
public static void main(String[] args) {
handle("2 2", "200 200");
}
/**
*
* @param people
* @param ratio
* 构建动态方程
* 假设M个医生、N个志愿者 dp[M][N]
* 则最后一个医生的分配规则 = 如果没有志愿者 dp[M-1][N] + M医生的效率减少0.2
* 如果分配一个志愿者 dp[M-1][N-1] + M医生的效率 和 没有志愿者时的效率 取最优值 【dp[M-1][N-1]的效率已求得最优】
* 如果分配两个志愿者 dp[M-1][N-2] + M医生的效率 + M医生浮动粒度的2倍 和 分配一个志愿者 取最优值 【dp[M-1][N-2]的效率已求得最优】
* 如果分配三个志愿者 dp[M-1][N-3] + M医生的效率 + M医生浮动粒度的3倍 和 分配两个志愿者 取最优值 【dp[M-1][N-3]的效率已求得最优】
*
*/
public static void handle(String people, String ratio) {
String[] p = people.split(" ");
int doctors_num = Integer.parseInt(p[0]);
Integer[] every_ratio = new Integer[Integer.parseInt(p[0])];
int volunteer = Integer.parseInt(p[1]);
String[] everyRatio = ratio.split(" ");
for (int i = 0; i < everyRatio.length; i++) {
every_ratio[i] = Integer.parseInt(everyRatio[i]);
}
int[][] dp = new int[doctors_num + 1][volunteer + 1];
for (int i = 1; i <= doctors_num; i++) {
for (int j = 0; j <= volunteer; j++) {
Integer the_ratio = every_ratio[i - 1];
int no_volunteer = the_ratio - (int) (the_ratio * 0.2);
//如果增加一个医生,不分配志愿者
dp[i][j] = dp[i - 1][j] + no_volunteer;
if (j >= 1) {
//如果增加一个医生,分配一个志愿者
dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - 1] + the_ratio);
}
if (j >= 2) {
//如果增加一个医生,分配两个志愿者
dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - 2] + the_ratio + (int) (the_ratio * 0.1));
}
if (j >= 3) {
//如果增加一个医生,分配三个志愿者
dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - 2] + the_ratio + (int) (the_ratio * 0.1) * 2);
}
if (j >= 4) {
//如果增加一个医生,分配四个志愿者
dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - 4] + the_ratio + (int) (the_ratio * 0.1) * 3);
}
}
}
System.out.println(dp[doctors_num][volunteer]);
}
}