和谐程序组

和谐程序组

问题背景

在一个计算机系统中,存在多个待运行的程序。部分程序之间存在互斥关系,意味着它们不能同时运行。我们需要从所有程序中找出一个符合特定规则的"和谐"子集。

核心定义

  1. 互斥(Mutually Exclusive):

    如果两个程序是互斥的,它们就不能被放入同一个程序组中。

  2. 和谐程序组(Harmonious Program Group):

    一个程序的集合,如果其中任意两个程序之间都不存在互斥关系,那么这个集合就被称为一个"和谐程序组"。

筛选规则

我们需要在所有可能的"和谐程序组"中,通过以下两条规则筛选出唯一的目标程序组:

  • 规则 1 (数量最多) : 首先,目标程序组的程序数量必须是最多的。
  • 规则 2 (运行时间之和最小) : 如果满足规则1的程序组有多个(即数量最多的和谐程序组不唯一),则在这些候选项中,选择那个所有程序运行时间之和最小的。

任务要求

给定所有程序的运行时间 appRunTimes 和一个描述互斥关系的列表 mutexs,请找出最终符合上述双重规则的目标和谐程序组,并返回该组所有程序的运行时间总和。


输入格式

  • appRunTimes: 第一个参数,一个整数数组。

    • 数组的下标 i 表示程序编号 ,值为 appRunTimes[i],表示对应程序的运行时间。
    • 1 <= appRunTimes.length <= 20
    • 1 <= appRunTimes[i] <= 100
  • mutexs: 第二个参数,一个二维整数数组,代表互斥程序对列表。

    • mutexs 中的每个元素 [prog1, prog2] 表示程序 prog1prog2 之间存在互斥关系。
    • 1 <= mutexs.length <= appRunTimes.length * (appRunTimes.length - 1) / 2
    • 0 <= prog1, prog2 < appRunTimes.length (程序编号与 appRunTimes 的下标对应)。

输出格式

  • 一个整数,表示最终选出的那个和谐程序组的所有程序运行时间之和。

样例说明

样例 1

  • 输入:

    • appRunTimes = [1, 2, 10]
    • mutexs = [[0, 1]] (注意:根据题目解释,我们假设互斥对指的是程序编号/数组下标)
  • 输出 : 11

  • 解释:

    1. 程序信息:

      • 程序 0: 运行时间 1
      • 程序 1: 运行时间 2
      • 程序 2: 运行时间 10
    2. 互斥关系: 程序 0 和程序 1 互斥。

    3. 寻找所有和谐程序组:

      • {0, 2} (程序0和程序2不互斥)
      • {1, 2} (程序1和程序2不互斥)
      • {0}, {1}, {2} (单个程序的组总是和谐的)
      • ... 其他如 {0, 1} 因互斥被排除。
    4. 应用规则 1 (数量最多) :

      • 数量最多的和谐程序组包含 2 个程序。符合条件的组是 {0, 2}{1, 2}
    5. 应用规则 2 (运行时间之和最小) :

      • 计算这两个候选组的运行时间之和:

        • {0, 2} 的和: appRunTimes[0] + appRunTimes[2] = 1 + 10 = 11
        • {1, 2} 的和: appRunTimes[1] + appRunTimes[2] = 2 + 10 = 12
      • 11 < 12,因此选择 {0, 2}

    6. 最终结果 : 返回其运行时间之和 11

(注:原样例解释中 "程序1+程序3" 的说法可能存在歧义,此处以上述基于数组下标的解释为准,该解释能严谨地推导出样例结果。)

样例 2

  • 输入:

    • appRunTimes = [1]
    • mutexs = []
  • 输出 : 1

  • 解释:

    • 只有一个程序(程序 0),运行时间为 1。
    • 没有互斥关系。
    • 唯一且最大的和谐程序组就是 {0} 本身。
    • 其运行时间之和为 1。

思考过程

  1. 问题的本质是什么?

    1. 我们需要从所有可能的"和谐程序组"(即内部没有互斥对的程序集合)中,找出一个"最佳"的组。

    2. "最佳"的定义有两条,按优先级排序:

      • 程序数量最多。
      • 在数量最多的前提下,运行时间总和最小。
  2. 如何表示一个"程序组"?

    1. 既然总程序数 n 不超过 20,我们可以用一个整数的二进制位来表示一个程序组(子集)。一个 int 类型有 32 位,足够了。
    2. 例如,如果我们有 5 个程序(编号 0 到 4),那么整数 13 的二进制是 01101
    3. 我们可以规定,从右往左,第 i 位是 1 表示程序 i 在这个组里,是 0 表示不在。
    4. 那么 01101 就代表了包含程序 {0, 2, 3} 的程序组。
    5. 这样,从 02^n - 1 的所有整数就唯一地对应了所有可能的程序组。
  3. 如何高效地判断 互斥 关系?

    1. 在检查一个程序组是否"和谐"时,我们需要快速判断任意两个程序是否互斥。
    2. 最好的方法是预处理 mutexs 数据,将其存入一个邻接矩阵 (一个二维布尔数组 isMutex[n][n])。
    3. isMutex[i][j] = true 表示程序 ij 互斥。由于互斥是双向的,所以 isMutex[j][i] 也应该是 true
    4. 这样,判断 ij 是否互斥就变成了 O(1) 的数组查询。
java 复制代码
import java.util.Arrays;

class Solution {
    /**
     * 寻找最佳和谐程序组并返回其总运行时间。
     *
     * @param appRunTimes 一个数组,其索引 i 代表程序编号,值代表运行时间。
     * @param mutexs      一个二维数组,每个元素 [p1, p2] 代表一对互斥的程序。
     * @return 满足条件的最佳和谐程序组的运行时间之和。
     */
    public int findBestGroupSum(int[] appRunTimes, int[][] mutexs) {
        int n = appRunTimes.length; // 程序的总数

        // 1. 构建互斥关系的邻接矩阵,方便 O(1) 查询
        // isMutex[i][j] = true 表示程序 i 和 j 互斥
        boolean[][] isMutex = new boolean[n][n];
        for (int[] pair : mutexs) {
            // 注意:题目给的程序编号可能是 1-based 或 0-based。
            // 从样例看,[1,2,10] 和 [[1,2]],程序编号是 0,1,2。所以 mutexs 里的编号也是 0-based。
            // 如果是 1-based,则需要减 1。这里我们按 0-based 处理。
            int p1 = pair[0];
            int p2 = pair[1];
            isMutex[p1][p2] = true;
            isMutex[p2][p1] = true; // 互斥关系是双向的
        }

        // 2. 初始化用于存储最佳结果的变量
        int maxSize = 0;           // 记录找到的最大的和谐程序组的大小
        int minSumForMaxSize = 0;  // 记录在 maxSize 下,最小的运行时间总和

        // 3. 使用位掩码遍历所有 2^n 个可能的程序子集
        // mask 的范围从 1 到 (1 << n) - 1。我们从 1 开始,因为空集不可能是答案。
        // (1 << n) 等价于 2^n
        for (int mask = 1; mask < (1 << n); mask++) {
            // a. 检查当前子集 (由 mask 代表) 是否和谐
            boolean isHarmonious = true;
            // 遍历所有可能的程序对 (i, j)
            for (int i = 0; i < n; i++) {
                // 检查程序 i 是否在当前子集中
                // (mask >> i) & 1 == 1 是一个检查第 i 位是否为 1 的标准技巧
                if (((mask >> i) & 1) == 1) {
                    for (int j = i + 1; j < n; j++) {
                        // 检查程序 j 是否也在当前子集中
                        if (((mask >> j) & 1) == 1) {
                            // 如果 i 和 j 都在子集中,检查它们是否互斥
                            if (isMutex[i][j]) {
                                isHarmonious = false; // 发现互斥对,此子集不和谐
                                break; // 内层循环没必要继续了
                            }
                        }
                    }
                }
                if (!isHarmonious) {
                    break; // 外层循环也没必要继续了
                }
            }
            
            // 如果当前子集不和谐,跳过,继续检查下一个 mask
            if (!isHarmonious) {
                continue;
            }
            
            // b. 如果子集是和谐的,计算它的大小和运行时间总和
            int currentSize = Integer.bitCount(mask); // bitCount() 快速计算整数中 1 的个数
            int currentSum = 0;
            for (int i = 0; i < n; i++) {
                if (((mask >> i) & 1) == 1) { // 如果程序 i 在子集中
                    currentSum += appRunTimes[i];
                }
            }

            // c. 根据规则更新最佳结果
            // 规则1:程序数量最多
            if (currentSize > maxSize) {
                maxSize = currentSize;         // 找到了一个更大的和谐组
                minSumForMaxSize = currentSum; // 直接更新,因为这是目前最大组的唯一总和
            } 
            // 规则2:如果数量相同,则运行时间总和最小
            else if (currentSize == maxSize) {
                minSumForMaxSize = Math.min(minSumForMaxSize, currentSum); // 取更小的总和
            }
        }

        // 4. 返回最终结果
        return minSumForMaxSize;
    }
}

class Main {
    public static void main(String[] args) {
        Solution solver = new Solution();
        
        // 样例1
        int[] appRunTimes1 = {1, 2, 10};
        int[][] mutexs1 = {{1, 2}};
        int result1 = solver.findBestGroupSum(appRunTimes1, mutexs1);
        System.out.println("样例 1 输出: " + result1); // 预期: 11
        // 解释:
        // 和谐组: {0}, {1}, {2}, {0,2}
        // 大小为1的组: {0}(1), {1}(2), {2}(10)
        // 大小为2的组: {0,2}(11)
        // 最大大小为2,其唯一总和是11

        // 样例2
        int[] appRunTimes2 = {1};
        int[][] mutexs2 = {};
        int result2 = solver.findBestGroupSum(appRunTimes2, mutexs2);
        System.out.println("样例 2 输出: " + result2); // 预期: 1
        // 解释: 和谐组: {0}。最大大小1,总和1
    }
}
相关推荐
Jinkxs10 分钟前
Spring MVC 执行流程详解:一次请求经历了什么?
java·spring·mvc
程序无bug21 分钟前
Java 服务性能优化,提升QPS
java·后端
阑梦清川25 分钟前
使用C语言原生的字符串函数求解的一道题目总结
算法
阑梦清川26 分钟前
算法竞赛小白晋级之路---高精度减法(题目+解析+代码)
算法
2401_8812444031 分钟前
牛客周赛 Round 100
算法
Java技术小馆35 分钟前
5种禁止用户复制的实用方案
java·面试·架构
duration~1 小时前
Spring AI快速入门
java·人工智能·后端·spring·flask
没有羊的王K1 小时前
SSM框架学习——day3
java·spring boot·学习
月堂1 小时前
【无标题】
java·linux·windows
GG不是gg1 小时前
详解SPFA算法-单源最短路径求解
算法·图论