Arrays.fill(dp, Integer.MAX_VALUE)

本文解释了如何在Java中使用Arrays.fill()函数将数组dp的所有元素设置为整型最大值Integer.MAX_VALUE,此操作常见于算法和动态规划的初始化过程,便于后续比较和更新。

Java中的Arrays.fill()函数来将数组dp中的所有元素都填充为Integer.MAX_VALUE,即整型变量能表示的最大值。

Arrays.fill()函数用于将指定的值赋给数组中的每个元素,其语法如下:

public static void fill(int[] array, int value)

其中,array表示要填充的数组,value表示要赋给数组元素的值。

在这段代码中,Arrays.fill(dp, Integer.MAX_VALUE)将数组dp中的每个元素都赋为Integer.MAX_VALUE,即整型变量能表示的最大值。

这通常用于算法或动态规划问题中,将数组初始化为一个较大的数值,以便在后续的计算中进行比较和更新操作。

import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class MilkTeaShopLocation { // 输入参数(可根据实际场景调整) private static final int n = 8; // 区域数量(0~7) private static final int[] p = {50, 80, 120, 60, 150, 90, 70, 110}; // 各区域人流量 private static final int L = 1; // 有效覆盖范围(距离≤1的区域) private static final int C = 2000; // 单店开设成本(元) private static final int R = 20; // 单位人流量收益(元/人) private static final int k = 2; // 计划开设奶茶店数量 // 前缀和数组(预处理人流量总和) private static int[] prefixSum; // DP数组:dp[i][j] = 前i个区域开j家店,第j家在i-1号区域的最大利润 private static int[][] dp; // 回溯数组:记录dp[i][j]的最优前驱m(用于查找选址方案) private static int[][] prev; /** * 预处理前缀和数组 */ private static void initPrefixSum() { prefixSum = new int[n + 1]; for (int i = 0; i < n; i++) { prefixSum[i + 1] = prefixSum[i] + p[i]; } } /** * 动态规划计算最大利润 * @return 最大利润(若为-∞表示无可行方案) */ private static int calculateMaxProfit() { // 初始化DP数组和回溯数组 dp = new int[n + 1][k + 1]; prev = new int[n + 1][k + 1]; for (int i = 0; i <= n; i++) { Arrays.fill(dp[i], Integer.MIN_VALUE / 2); // 避免溢出 Arrays.fill(prev[i], -1); } // 1. 初始状态:j=1(开1家店) for (int i = 1; i <= n; i++) { int shopLoc = i - 1; // 奶茶店开设在第i-1号区域 int left = Math.max(0, shopLoc - L); int right = Math.min(n - 1, shopLoc + L); int totalPeople = prefixSum[right + 1] - prefixSum[left]; int profit = totalPeople * R - C; if (profit > 0) { // 利润为负时不开店(可选:允许负利润则直接赋值) dp[i][1] = profit; } } // 2. 状态转移:j≥2(开j家店) for (int j = 2; j <= k; j++) { for (int i = j; i <= n; i++) { // 前i个区域开j家,i至少为j(每个店占1个区域) int currentShopLoc = i - 1; // 当前第j家店的位置 // 遍历前驱m:前m个区域开j-1家,m的范围是[j-1, currentShopLoc - L - 1](两店距离> L) int maxPrevM = currentShopLoc - L - 1; if (maxPrevM < j - 1) continue; // 前m个区域至少能开j-1家店(m≥j-1) for (int m = j - 1; m <= maxPrevM; m++) { if (dp[m][j - 1] == Integer.MIN_VALUE / 2) continue; // 前驱状态不可行 // 计算当前店的覆盖范围(左边界=前一家店的位置+1,避免分流) int left = Math.max(m, currentShopLoc - L); // m是前m个区域的最后一个,对应位置m-1,左边界≥m int right = Math.min(n - 1, currentShopLoc + L); int totalPeople = prefixSum[right + 1] - prefixSum[left]; int currentProfit = totalPeople * R - C; int totalProfit = dp[m][j - 1] + currentProfit; // 更新DP值和回溯记录 if (totalProfit > dp[i][j]) { dp[i][j] = totalProfit; prev[i][j] = m; } } } } // 3. 提取最大利润(前i个区域开k家店的所有可能) int maxProfit = Integer.MIN_VALUE / 2; for (int i = k; i <= n; i++) { maxProfit = Math.max(maxProfit, dp[i][k]); } return maxProfit; } /** * 回溯查找最优选址方案(奶茶店所在区域编号) * @return 最优选址列表(按开设顺序排列) */ private static List<Integer> findOptimalLocations() { List<Integer> locations = new ArrayList<>(); int maxProfit = Integer.MIN_VALUE / 2; int lastI = -1; // 找到最后一家店的位置对应的i for (int i = k; i <= n; i++) { if (dp[i][k] > maxProfit) { maxProfit = dp[i][k]; lastI = i; } } if (lastI == -1) return locations; // 无可行方案 // 回溯查找所有店的位置 int j = k; int i = lastI; while (j > 0 && i != -1) { locations.add(i - 1); // 店的位置是i-1(前i个区域的最后一个区域) i = prev[i][j]; j--; } // 反转列表,按区域编号升序排列 java.util.Collections.reverse(locations); return locations; } /** * 暴力枚举所有方案(验证动态规划结果正确性) */ private static void verifyByBruteForce() { System.out.println("\n=== 暴力枚举验证(所有" + k + "家店组合)==="); List<List<Integer>> allCombinations = new ArrayList<>(); generateCombinations(0, new ArrayList<>(), k, allCombinations); int maxBruteProfit = Integer.MIN_VALUE; List<Integer> bestBruteLocation = new ArrayList<>(); for (List<Integer> locs : allCombinations) { int profit = calculateProfit(locs); if (profit > maxBruteProfit) { maxBruteProfit = profit; bestBruteLocation = locs; } System.out.printf("选址方案:%s → 利润:%d元%n", locs, profit); } System.out.printf("暴力枚举最优方案:%s → 最大利润:%d元%n", bestBruteLocation, maxBruteProfit); } /** * 生成所有k个区域的组合(递归) */ private static void generateCombinations(int start, List<Integer> current, int k, List<List<Integer>> result) { if (current.size() == k) { result.add(new ArrayList<>(current)); return; } for (int i = start; i < n; i++) { current.add(i); generateCombinations(i + 1, current, k, result); current.remove(current.size() - 1); } } /** * 计算指定选址方案的利润(暴力枚举用) */ private static int calculateProfit(List<Integer> locations) { if (locations.size() != k) return Integer.MIN_VALUE / 2; // 标记每个区域的归属(最近的奶茶店)和人流量分配 int[] belong = new int[n]; // -1=未分配,0~k-1=归属第i家店 int[] peoplePerShop = new int[k]; Arrays.fill(belong, -1); for (int area = 0; area < n; area++) { int minDist = Integer.MAX_VALUE; int bestShop = -1; // 找最近的奶茶店 for (int s = 0; s < locations.size(); s++) { int dist = Math.abs(area - locations.get(s)); if (dist < minDist) { minDist = dist; bestShop = s; } } // 仅在覆盖范围内才分配 if (minDist <= L) { peoplePerShop[bestShop] += p[area]; } } // 计算总利润 int totalRevenue = 0; for (int people : peoplePerShop) { totalRevenue += people * R; } int totalCost = k * C; return totalRevenue - totalCost; } /** * 打印输入参数和DP数组(调试用) */ private static void printParamsAndDP() { System.out.println("=== 输入参数 ==="); System.out.printf("区域数量:%d个(编号0~%d)%n", n, n-1); System.out.printf("各区域人流量:%s%n", Arrays.toString(p)); System.out.printf("覆盖范围L:%d(距离≤%d的区域)%n", L, L); System.out.printf("单店开设成本C:%d元%n", C); System.out.printf("单位人流量收益R:%d元/人%n", R); System.out.printf("计划开店数量k:%d家%n", k); System.out.printf("前缀和数组:%s%n", Arrays.toString(prefixSum)); System.out.println("\n=== DP数组(dp[i][j]:前i个区域开j家店的最大利润)==="); for (int j = 0; j <= k; j++) { for (int i = 0; i <= n; i++) { if (dp[i][j] == Integer.MIN_VALUE / 2) { System.out.printf("%6s", "∞"); } else { System.out.printf("%6d", dp[i][j]); } } System.out.println(); } } public static void main(String[] args) { System.out.println("=== 奶茶店选址优化(动态规划实现)==="); // 初始化前缀和 initPrefixSum(); // 动态规划计算最大利润 int maxProfit = calculateMaxProfit(); // 查找最优选址方案 List<Integer> optimalLocations = findOptimalLocations(); // 打印参数和DP数组 printParamsAndDP(); // 输出最优结果 System.out.println("\n=== 动态规划最优结果 ==="); if (maxProfit <= 0 || optimalLocations.isEmpty()) { System.out.println("❌ 无可行选址方案(利润≤0或无法满足开店数量)"); } else { System.out.printf("✅ 最大利润:%d元%n", maxProfit); System.out.printf("✅ 最优选址:%s(区域编号)%n", optimalLocations); } // 暴力枚举验证 verifyByBruteForce(); } }详细解析这段算法
最新发布
11-28
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值