华为OD机试新系统真题【云服务安全策略最优选择】

云服务安全策略最优选择(C/C++/Py/Java/Js/Go)题解

华为OD机试新系统真题 华为OD上机考试新系统真题 6月24号 200分题型

华为OD机试新系统真题目录点击查看: 华为OD机试新系统真题题库目录|机考题库 + 算法考点详解

题目内容

在云服务中,有 n n n 个安全策略,编号 1 1 1 到 n n n。每个策略有一个重要度权重(正整数)。某些策略对之间互斥,不能同时启用。

现在需要为某个实例恰好选择 k k k 个策略,要求:

  1. 选中的策略之间没有互斥关系(即构成一个独立集);
  2. 在满足条件1的所有大小为 k k k 的策略组合中,使得选中策略的权重之和最大(权重之和就是重要度权重数组中的权重的和)
    请返回所有满足上述条件的最优策略组合(即权重和最大的所有合法组合)。

输入描述

  • 第一行:整数 n n n(策略总数)
  • 第二行:整数 k k k(需要选择的策略数量)
  • 第三行:长度为 n n n 的整数数组 w e i g h t s weights weights,其中 w e i g h t s i weightsi weightsi 表示策略 i + 1 i+1 i+1 的权重, 字符串表示通过,分割
  • 第四行:二维整数数组 c o n f l i c t s conflicts conflicts,每个元素为 a a a, b b b,表示策略 a a a 和 b b b 互斥(无向,无重复边),通过字符串表示,a和b之间通过,分割,不同组通过空格分割

数据规模:

  • 1 ≤ n ≤ 25 1 \le n \le 25 1≤n≤25
  • 0 ≤ k ≤ n 0 \le k \le n 0≤k≤n
  • 1 ≤ 1 \le 1≤ w e i g h t s weights weights i i i ≤ 1000 \le 1000 ≤1000
  • 0 ≤ 0 \le 0≤ c o n f l i c t s . l e n g t h conflicts.length conflicts.length ≤ n ( n − 1 ) / 2 \le n(n-1)/2 ≤n(n−1)/2

输出描述

  • 每个组合内的策略编号按升序排列;
  • 所有组合按字典序排列(将每个组合视为一个数字序列);
  • 如果没有合法组合(例如不存在大小为 k k k 的独立集),则返回空数组 \[\]。

注意

  • 如果没有大小为 k k k 的独立集,则返回 空

样例1

输入

复制代码
4
2
5,1,3,4
1,2 2,3

输出

复制代码
1,4

说明

所有大小为 2 2 2 的策略组合及互斥检查:

  • 1,2 冲突不考虑
  • 1,3 不冲突,5 + 3 = 8
  • 1,4 不冲突,5 + 4 = 9
  • 2,3冲突,不考虑
  • 2,4不冲突,1 +4=5
  • 3,4不冲突,3 + 4 = 7
  • 所以结果为1,4

样例2

输入

复制代码
5
3
3,4,3,4,3
1,3 2,4 3,5

输出

复制代码
1,2,5 1,4,5

说明

所有大小为3且无互斥的组合:

  • 1,2,3冲突
  • 1,2,4冲突
  • 1,2,5不冲突,3 + 4 +3 = 10
  • 1,3,4冲突
  • 1,3,5冲突
  • 1,4,5不冲突,3+4+3=10
  • 2,3,4冲突
  • 2,3,5冲突
  • 2,4,5冲突
  • 3,4,5冲突
  • 合法组合只有1,2,51,4,5权重和均为10,按字典序进行排序输出。

题解

思路:递归回溯

  1. 总体思路就是从n中选择k个互不冲突的策略方案,记录其中方案权重和最大值maxWeightSum和权重和为maxWeightSum的具体方案。

  2. 递归回溯代码基本就是模板,具体剪枝和逻辑代码可参照下面代码,这里主要说说快速判断进行冲突判断。

  3. 本题中n <= 25,可以预处理每个策略 与其冲突的策略使用conflictMask数组存储,每个冲突情况使用二进制位形式表示,bitmask,例如策略1,与策略2,策略3冲突时对应二进制位110. 这样在进行递归回溯时,当前已选择策略的mask为selectedMask,判断策略i能否选取只需要进行conflictMask[i] & selectedMask == 0与运算结果判断就行。

C++

cpp 复制代码
#include <algorithm>
#include<bits/stdc++.h>
#include <string>
#include <vector>
using namespace std;

// 当前最大权重和
int maxWeightSum = 0;
// 所有最优方案
vector<vector<int>> ans;

// conflict[i]值对应二进制位1位置表示和i冲突
vector<int> conflictMask;
// 通用 切割函数 函数 将字符串str根据delimiter进行切割
vector<string> split(const string& str, const string& delimiter) {
    vector<string> result;
    size_t start = 0;
    size_t end = str.find(delimiter);
    while (end != string::npos) {
        result.push_back(str.substr(start, end - start));
        start = end + delimiter.length();
        end = str.find(delimiter, start);
    }
    // 添加最后一个部分
    result.push_back(str.substr(start));
    return result;
}


void dfs(int n, int k, int idx,int selectedMask ,vector<int>& weights, vector<int>& path) {
    // 剩余数量剪枝
    if (path.size() + (n - idx) < k) return;
    if (path.size() == k) {
        int weightSum = 0;
        for (int i = 0; i < k; i++) {
            weightSum += weights[path[i] - 1];
        }
        if (weightSum > maxWeightSum) {
            maxWeightSum = weightSum;
            ans.clear();
            ans.push_back(path);
        } else if (weightSum == maxWeightSum) {
            ans.push_back(path);
        }
        return;
    } 

    if (idx >= n) {
        return;
    }

    for (int i = idx; i < n; i++) {
        // 冲突判断
        if ((conflictMask[i] & selectedMask) == 0) {
            path.push_back(i + 1);
            dfs(n, k, i + 1, selectedMask | (1 << i), weights, path);
            // 回溯
            path.pop_back();    
        }
    }
}


vector<vector<int>> selectSchema(int n, int k, vector<int>& weights, vector<vector<int>>& conflicts) {
    // 特例
    if (k == 0) {
        return {};
    }
    conflictMask.assign(n, 0);
    // 将冲突转换为对应mask
    for (int i = 0; i < conflicts.size(); i++) {
        int a = conflicts[i][0] - 1;
        int b = conflicts[i][1] - 1;
        conflictMask[a] |= (1 << b);
        conflictMask[b] |= (1 << a);
    }
    vector<int> path;
    dfs(n, k, 0, 0, weights, path);
    return ans;
}

int main() {
    int n ,k;
    cin >> n;
    cin >> k;
    // 忽略空行
    cin.ignore();
    string input;
    getline(cin, input);
    vector<string> tmp1 = split(input, ",");
    vector<int> weights(tmp1.size());
    for (int i = 0; i < tmp1.size(); i++) {
        weights[i] = stoi(tmp1[i]);
    }

    vector<vector<int>> conflicts;
    string input2;
    getline(cin, input2);
    if (!input2.empty()) {
        vector<string> tmp2 = split(input2, " ");
        for (int i = 0; i < tmp2.size(); i++) {
            vector<string> tmp3 = split(tmp2[i], ",");
            conflicts.push_back({stoi(tmp3[0]), stoi(tmp3[1])});
        }
    }

    vector<vector<int>> ans = selectSchema(n, k, weights, conflicts);
    // 输出结果
    for (int i = 0; i < ans.size(); i++) {
        if (i > 0) {
            cout << " ";
        }
        for (int j = 0; j < k; j++) {
            if (j > 0) {
                cout << ",";
            }
            cout << ans[i][j];
        }
    }
    return 0;
}

JAVA

java 复制代码
import java.util.*;

public class Main {

    static int n, k;
    // 当前最大权重和
    static int maxWeightSum = 0;
   // 所有最优方案
    static List<List<Integer>> ans = new ArrayList<>();
    static List<Integer> path = new ArrayList<>();

    // conflict[i]值对应二进制位1位置表示和i冲突
    static int[] conflictMask;
    static int[] weights;

    // DFS
    static void dfs(int idx, int selectedMask) {

        // 剩余数量剪枝
        if (path.size() + (n - idx) < k) return;

        if (path.size() == k) {

            int sum = 0;
            for (int i = 0; i < k; i++) {
                sum += weights[path.get(i) - 1];
            }

            if (sum > maxWeightSum) {
                maxWeightSum = sum;
                ans.clear();
                ans.add(new ArrayList<>(path));
            } else if (sum == maxWeightSum) {
                ans.add(new ArrayList<>(path));
            }
            return;
        }

        for (int i = idx; i < n; i++) {
            // 冲突检测
            if ((conflictMask[i] & selectedMask) == 0) {
                path.add(i + 1);
                dfs(i + 1, selectedMask | (1 << i));
                path.remove(path.size() - 1);
            }
        }
    }

    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);

        n = Integer.parseInt(sc.nextLine());
        k = Integer.parseInt(sc.nextLine());

        String[] w = sc.nextLine().split(",");
        weights = new int[n];
        for (int i = 0; i < n; i++) weights[i] = Integer.parseInt(w[i]);

        conflictMask = new int[n];

        if (sc.hasNextLine()) {
            String line = sc.nextLine().trim();
            if (!line.isEmpty()) {
                for (String p : line.split(" ")) {
                    String[] ab = p.split(",");
                    int a = Integer.parseInt(ab[0]) - 1;
                    int b = Integer.parseInt(ab[1]) - 1;
                    conflictMask[a] |= (1 << b);
                    conflictMask[b] |= (1 << a);
                }
            }
        }

        dfs(0, 0);

        for (int i = 0; i < ans.size(); i++) {
            if (i > 0) System.out.print(" ");
            for (int j = 0; j < ans.get(i).size(); j++) {
                if (j > 0) System.out.print(",");
                System.out.print(ans.get(i).get(j));
            }
        }
    }
}

Python

python 复制代码
import sys
# 当前最大权重和
maxWeightSum = 0
# 所有最优方案
ans = []
path = []
# conflictMask[i]:第i个点的冲突集合(bitmask表示)
conflictMask = []
weights = []
n = k = 0


# DFS
def dfs(idx, selectedMask):
    global maxWeightSum, ans

    # 剩余数量剪枝
    if len(path) + (n - idx) < k:
        return

    if len(path) == k:
        s = 0
        for i in range(k):
            s += weights[path[i] - 1]

        if s > maxWeightSum:
            maxWeightSum = s
            ans = [path[:]]
        elif s == maxWeightSum:
            ans.append(path[:])
        return

    for i in range(idx, n):
        # 冲突检测
        if (conflictMask[i] & selectedMask) == 0:
            path.append(i + 1)
            dfs(i + 1, selectedMask | (1 << i))
            path.pop()


n = int(sys.stdin.readline())
k = int(sys.stdin.readline())

weights = list(map(int, sys.stdin.readline().strip().split(",")))
conflictMask = [0] * n

line = sys.stdin.readline().strip()
if line:
    for p in line.split():
        a, b = map(int, p.split(","))
        conflictMask[a - 1] |= (1 << (b - 1))
        conflictMask[b - 1] |= (1 << (a - 1))

dfs(0, 0)

for i, g in enumerate(ans):
    if i > 0:
        print(" ", end="")
    print(",".join(map(str, g)), end="")

JavaScript

js 复制代码
const readline = require('readline');

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

let input = [];

// maxWeightSum:当前最大权重和
let maxWeightSum = 0;

// ans:所有最优方案
let ans = [];

// path:当前路径
let path = [];

// conflictMask[i]:第i个点的冲突集合(bitmask表示)
let conflictMask = [];

// weights:权重数组
let weights = [];

// n,k
let n = 0, k = 0;

rl.on('line', (line) => {
    input.push(line.trim());
});

rl.on('close', () => {

    n = Number(input[0]);
    k = Number(input[1]);

    // 权重数组(逗号分隔)
    weights = input[2].split(',').map(Number);

    conflictMask = new Array(n).fill(0);

    // 冲突解析(空格分隔 pair)
    if (input[3] && input[3].length > 0) {
        let parts = input[3].split(' ');

        for (let p of parts) {
            let [a, b] = p.split(',').map(x => Number(x) - 1);

            // conflict[i]值对应二进制位1位置表示和i冲突
            conflictMask[a] |= (1 << b);
            conflictMask[b] |= (1 << a);
        }
    }

    dfs(0, 0);

    // 输出结果
    let out = ans.map(x => x.join(',')).join(' ');
    console.log(out);
});


function dfs(idx, selectedMask) {

    // 剩余数量剪枝
    if (path.length + (n - idx) < k) return;

    if (path.length === k) {

        let sum = 0;

        for (let i = 0; i < k; i++) {
            sum += weights[path[i] - 1];
        }

        if (sum > maxWeightSum) {
            maxWeightSum = sum;
            ans = [path.slice()];
        } else if (sum === maxWeightSum) {
            ans.push(path.slice());
        }
        return;
    }

    if (idx >= n) return;

    for (let i = idx; i < n; i++) {

        // 冲突判断
        if ((conflictMask[i] & selectedMask) === 0) {

            path.push(i + 1);

            dfs(i + 1, selectedMask | (1 << i));

            // 回溯
            path.pop();
        }
    }
}

Go

go 复制代码
package main

import (
    "bufio"
    "fmt"
    "os"
    "strconv"
    "strings"
)

var (
    n, k int
    // 当前最大权重和
    maxWeightSum int
    // 所有最优方案
    ans [][]int
    path []int
   //  conflictMask[i]:第i个点的冲突集合(bitmask表示)
    conflictMask []int
    weights []int
)

// DFS
func dfs(idx int, selectedMask int) {

    // 剩余数量剪枝
    if len(path)+(n-idx) < k {
        return
    }

    if len(path) == k {

        sum := 0
        for i := 0; i < k; i++ {
            sum += weights[path[i]-1]
        }

        if sum > maxWeightSum {
            maxWeightSum = sum
            ans = [][]int{append([]int{}, path...)}
        } else if sum == maxWeightSum {
            ans = append(ans, append([]int{}, path...))
        }
        return
    }

    for i := idx; i < n; i++ {
        // 冲突检测
        if conflictMask[i]&selectedMask == 0 {
            path = append(path, i+1)
            dfs(i+1, selectedMask|(1<<i))
            path = path[:len(path)-1]
        }
    }
}

func main() {

    reader := bufio.NewReader(os.Stdin)

    fmt.Fscanln(reader, &n)
    fmt.Fscanln(reader, &k)

    line, _ := reader.ReadString('\n')
    line = strings.TrimSpace(line)

    w := strings.Split(line, ",")
    weights = make([]int, n)

    for i := 0; i < n; i++ {
        weights[i], _ = strconv.Atoi(w[i])
    }

    conflictMask = make([]int, n)

    line, _ = reader.ReadString('\n')
    line = strings.TrimSpace(line)

    if line != "" {
        for _, p := range strings.Split(line, " ") {
            ab := strings.Split(p, ",")
            a, _ := strconv.Atoi(ab[0])
            b, _ := strconv.Atoi(ab[1])
            a--
            b--
            conflictMask[a] |= 1 << b
            conflictMask[b] |= 1 << a
        }
    }

    dfs(0, 0)

    for i, g := range ans {
        if i > 0 {
            fmt.Print(" ")
        }
        for j, v := range g {
            if j > 0 {
                fmt.Print(",")
            }
            fmt.Print(v)
        }
    }
}

C语言

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXN 25

int n, k;
// 当前最大权重和
int maxWeightSum = 0;

int weights[MAXN];
// conflictMask[i]:第i个点的冲突集合(bitmask表示)
int conflictMask[MAXN];

int path[MAXN];
int pathSize = 0;
// 存储所有最佳结果
int ans[MAXN][MAXN];
int ansCount = 0;

// DFS
void dfs(int idx, int selectedMask) {

    // 剩余数量剪枝
    if (pathSize + (n - idx) < k) return;

    if (pathSize == k) {

        int sum = 0;
        for (int i = 0; i < k; i++) {
            sum += weights[path[i] - 1];
        }

        if (sum > maxWeightSum) {
            maxWeightSum = sum;
            ansCount = 0;
            memcpy(ans[ansCount], path, sizeof(int) * k);
            ansCount = 1;
        } else if (sum == maxWeightSum) {
            memcpy(ans[ansCount], path, sizeof(int) * k);
            ansCount++;
        }
        return;
    }

    for (int i = idx; i < n; i++) {
        if ((conflictMask[i] & selectedMask) == 0) {
            path[pathSize++] = i + 1;
            dfs(i + 1, selectedMask | (1 << i));
            pathSize--;
        }
    }
}

int main() {

    scanf("%d", &n);
    scanf("%d", &k);

    for (int i = 0; i < n; i++) {
        scanf("%d,", &weights[i]);
    }

    char buf[1000];
    getchar();
    fgets(buf, sizeof(buf), stdin);

    if (strlen(buf) > 1) {
        char *p = strtok(buf, " ");
        while (p) {
            int a, b;
            sscanf(p, "%d,%d", &a, &b);
            a--; b--;
            conflictMask[a] |= (1 << b);
            conflictMask[b] |= (1 << a);
            p = strtok(NULL, " ");
        }
    }

    dfs(0, 0);

    for (int i = 0; i < ansCount; i++) {
        for (int j = 0; j < k; j++) {
            if (j) printf(",");
            printf("%d", ans[i][j]);
        }
        if (i < ansCount - 1) printf(" ");
    }

    return 0;
}