手机多载波冲突选择(C++/Py/Java/Js/Go)题解
华为笔试真题 7月15号 非AI方向第二题 200分题型
题目内容
在手机通信中,为了提升网速,基站可以同时使用多个频段(称为载波聚合),每个频段提供一定的带宽,但存在以下限制:
- 每个频段最多选一个载波(不能同时选择同一频段的多个载波)。
- 冲突频段不能同时使用 (如 n1n1n1 和 n2n2n2 冲突,只能选其中一个)。
- 最多选择KKK个载波 (可以少于 KKK)。
你的任务是:
- 选择一组载波 ,使得 总带宽最大,同时满足上述约束。
- 输出最大总带宽 ,并给出所选载波的 编号。
输入描述
第一行 :NNN(载波总数,1≤N≤251 \le N \le 251≤N≤25)和 KKK(最多选 KKK 个载波,1≤K≤81 \le K \le 81≤K≤8,K≤NK \le NK≤N)。
第二行 :b1 b2 ... bNb1\ b2\ ...\ bNb1 b2 ... bN(每个载波的带宽,1≤bi≤10001 \le bi \le 10001≤bi≤1000)。
第三行 :f1 f2 ... fNf1\ f2\ ...\ fNf1 f2 ... fN(每个载波所属的频段,为 nnn 开头的字符串,如 n1n1n1、n2n2n2,不区分大小写,字符串长度不超过 101010)。
第四行 :CCC(冲突频段对数,0≤C≤250 \le C \le 250≤C≤25)。
接下来CCC行 :每行两个频段fa fbfa\ fbfa fb,表示 fafafa 和 fbfbfb 不能同时选(冲突关系不传递)。
输出描述
第一行 :最大总带宽。
第二行 :所选载波的 编号 (从 000 开始,按升序排列,数值序最小;组合有多种时,则输出数值序最小的一组)。
样例1
输入
6 2
100 200 150 300 250 180
n78 n41 n78 n28 n41 n28
1
n28 n41
输出
450
2 3
说明
选择带宽索引为 222 和 333 的两个带宽,即 150150150 和 300300300,总带宽为 450450450
样例2
输入
3 2
10 10 10
n1 n2 n3
0
输出
20
0 1
说明
最大带宽为 202020,因为每个频段带宽都相同,因此有 333 种组合:(0,1)(0,1)(0,1)、(0,2)(0,2)(0,2)、(1,2)(1,2)(1,2),输出排序后第一个组合 (0,1)(0,1)(0,1)
题解和思路
思路
实现思路:递归回溯
- 预处理根据
分组内只能任选一以及分组冲突关系提取出每个节点冲突节点的二进制表现形式。 - 递归回溯 枚举所有方案,用位运算快速判断是否合法,并保留合法组合方案最大带宽、最小字典序结果。
C++
cpp
#include <bits/stdc++.h>
using namespace std;
int n, k;
vector<int> b;
// 最大带宽
int maxB = 0;
vector<int> res;
// 将字符串转换为小写
string toLowerCase(string text) {
for (char &ch : text) {
ch = static_cast<char>(
tolower(static_cast<unsigned char>(ch))
);
}
return text;
}
// 递归回溯
void dfs(int index, vector<int>& path, int selectedMask, int sum, int count, vector<int>& bandConflictMask) {
if (index == n || count == k) {
if (sum > maxB) {
maxB = sum;
res = path;
}
return;
}
for (int i = index; i < n; i++) {
if ((selectedMask & bandConflictMask[i]) != 0) {
continue;
}
sum += b[i];
selectedMask |= (1 << i);
path.push_back(i);
dfs(i + 1, path, selectedMask, sum, count + 1, bandConflictMask);
sum -= b[i];
selectedMask -= (1 << i);
path.pop_back();
}
}
vector<int> getConflictMask(vector<string>& f, vector<pair<string,string>>& conflict) {
map<string, vector<int>> fPos;
for (int i = 0; i < n; i++) {
string lowF = toLowerCase(f[i]);
fPos[lowF].push_back(i);
}
// 每个频段拥有频段的mask表示形式
map<string, int> bandMask;
vector<int> bandConflictMask(n , 0);
for (auto[name, band] : fPos) {
int mask = 0;
for (int i = 0; i < band.size(); i++) {
int pos = band[i];
mask |= (1 << pos);
}
bandMask[name] = mask;
// 处理每个频段
for (int i = 0; i < band.size(); i++) {
int pos = band[i];
bandConflictMask[pos] = mask - (1 << pos);
}
}
// 处理冲突
for (int i = 0; i < conflict.size(); i++) {
string a = toLowerCase(conflict[i].first);
string b = toLowerCase(conflict[i].second);
if (bandMask.find(a) == bandMask.end() || bandMask.find(b) == bandMask.end()) {
continue;
}
int aMask = bandMask[a];
int bMask = bandMask[b];
vector<int> apos = fPos[a];
vector<int> bpos = fPos[b];
for (int i = 0; i < apos.size(); i++) {
bandConflictMask[apos[i]] |= bMask;
}
for (int i = 0; i < bpos.size(); i++) {
bandConflictMask[bpos[i]] |= aMask;
}
}
return bandConflictMask;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> k;
b.reserve(n);
for (int i = 0; i < n; i++) {
cin >> b[i];
}
vector<string> f(n);
for (int i = 0; i < n; i++) {
cin >> f[i];
}
int c;
cin >> c;
vector<pair<string,string>> conflict;
for (int i = 0; i < c; i++) {
string a, b;
cin >> a >> b;
conflict.push_back({a, b});
}
vector<int> bandConflictMask = getConflictMask(f, conflict);
vector<int> path;
dfs(0, path, 0, 0, 0, bandConflictMask);
cout << maxB << endl;
for (int i = 0; i < res.size(); i++) {
if (i > 0) {
cout << " ";
}
cout << res[i];
}
return 0;
}
Java
java
import java.util.*;
public class Main {
static int n, k;
static int[] b;
// 最大带宽
static int maxB = 0;
static List<Integer> res = new ArrayList<>();
// 将字符串转换为小写
static String toLowerCase(String text) {
return text.toLowerCase();
}
// 递归回溯
static void dfs(int index, List<Integer> path, int selectedMask, int sum, int count, int[] bandConflictMask) {
if (index == n || count == k) {
if (sum > maxB) {
maxB = sum;
res = new ArrayList<>(path);
}
return;
}
for (int i = index; i < n; i++) {
if ((selectedMask & bandConflictMask[i]) != 0) {
continue;
}
sum += b[i];
selectedMask |= (1 << i);
path.add(i);
dfs(i + 1, path, selectedMask, sum, count + 1, bandConflictMask);
sum -= b[i];
selectedMask ^= (1 << i);
path.remove(path.size() - 1);
}
}
static int[] getConflictMask(String[] f, List<String[]> conflict) {
Map<String, List<Integer>> fPos = new HashMap<>();
for (int i = 0; i < n; i++) {
String lowF = toLowerCase(f[i]);
fPos.computeIfAbsent(lowF, x -> new ArrayList<>()).add(i);
}
// 每个频段拥有频段的mask表示形式
Map<String, Integer> bandMask = new HashMap<>();
int[] bandConflictMask = new int[n];
for (Map.Entry<String, List<Integer>> entry : fPos.entrySet()) {
String name = entry.getKey();
List<Integer> band = entry.getValue();
int mask = 0;
for (int pos : band) {
mask |= (1 << pos);
}
bandMask.put(name, mask);
// 处理每个频段
for (int pos : band) {
bandConflictMask[pos] = mask ^ (1 << pos);
}
}
// 处理冲突
for (String[] item : conflict) {
String a = toLowerCase(item[0]);
String bb = toLowerCase(item[1]);
if (!bandMask.containsKey(a) || !bandMask.containsKey(bb)) {
continue;
}
int aMask = bandMask.get(a);
int bMask = bandMask.get(bb);
for (int pos : fPos.get(a)) {
bandConflictMask[pos] |= bMask;
}
for (int pos : fPos.get(bb)) {
bandConflictMask[pos] |= aMask;
}
}
return bandConflictMask;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
k = sc.nextInt();
b = new int[n];
for (int i = 0; i < n; i++) {
b[i] = sc.nextInt();
}
String[] f = new String[n];
for (int i = 0; i < n; i++) {
f[i] = sc.next();
}
int c = sc.nextInt();
List<String[]> conflict = new ArrayList<>();
for (int i = 0; i < c; i++) {
String a = sc.next();
String bb = sc.next();
conflict.add(new String[]{a, bb});
}
int[] bandConflictMask = getConflictMask(f, conflict);
dfs(0, new ArrayList<>(), 0, 0, 0, bandConflictMask);
System.out.println(maxB);
for (int i = 0; i < res.size(); i++) {
if (i > 0) {
System.out.print(" ");
}
System.out.print(res.get(i));
}
}
}
python
python
n, k = map(int, input().split())
b = list(map(int, input().split()))
# 最大带宽
maxB = 0
res = []
# 将字符串转换为小写
def toLowerCase(text):
return text.lower()
# 递归回溯
def dfs(index, path, selectedMask, total, count, bandConflictMask):
global maxB, res
if index == n or count == k:
if total > maxB:
maxB = total
res = path[:]
return
for i in range(index, n):
if (selectedMask & bandConflictMask[i]) != 0:
continue
path.append(i)
dfs(i + 1, path, selectedMask | (1 << i), total + b[i], count + 1, bandConflictMask)
path.pop()
def getConflictMask(f, conflict):
fPos = {}
for i in range(n):
lowF = toLowerCase(f[i])
fPos.setdefault(lowF, []).append(i)
# 每个频段拥有频段的mask表示形式
bandMask = {}
bandConflictMask = [0] * n
for name, band in fPos.items():
mask = 0
for pos in band:
mask |= 1 << pos
bandMask[name] = mask
# 处理每个频段
for pos in band:
bandConflictMask[pos] = mask ^ (1 << pos)
# 处理冲突
for a, bb in conflict:
a = toLowerCase(a)
bb = toLowerCase(bb)
if a not in bandMask or bb not in bandMask:
continue
aMask = bandMask[a]
bMask = bandMask[bb]
for pos in fPos[a]:
bandConflictMask[pos] |= bMask
for pos in fPos[bb]:
bandConflictMask[pos] |= aMask
return bandConflictMask
f = input().split()
c = int(input())
conflict = []
for _ in range(c):
conflict.append(input().split())
bandConflictMask = getConflictMask(f, conflict)
dfs(0, [], 0, 0, 0, bandConflictMask)
print(maxB)
print(*res)
Javascript
js
const readline = require("readline");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
const input = [];
rl.on("line", line => input.push(line));
rl.on("close", () => {
let idx = 0;
const [n, k] = input[idx++].split(" ").map(Number);
const b = input[idx++].split(" ").map(Number);
// 最大带宽
let maxB = 0;
let res = [];
// 将字符串转换为小写
function toLowerCase(text) {
return text.toLowerCase();
}
function getConflictMask(f, conflict) {
const fPos = new Map();
for (let i = 0; i < n; i++) {
const low = toLowerCase(f[i]);
if (!fPos.has(low)) fPos.set(low, []);
fPos.get(low).push(i);
}
// 每个频段拥有频段的mask表示形式
const bandMask = new Map();
const bandConflictMask = new Array(n).fill(0);
for (const [name, band] of fPos.entries()) {
let mask = 0;
for (const pos of band) {
mask |= (1 << pos);
}
bandMask.set(name, mask);
// 处理每个频段
for (const pos of band) {
bandConflictMask[pos] = mask ^ (1 << pos);
}
}
// 处理冲突
for (const [aa, bb] of conflict) {
const a = toLowerCase(aa);
const bName = toLowerCase(bb);
if (!bandMask.has(a) || !bandMask.has(bName)) continue;
const aMask = bandMask.get(a);
const bMask = bandMask.get(bName);
for (const pos of fPos.get(a)) {
bandConflictMask[pos] |= bMask;
}
for (const pos of fPos.get(bName)) {
bandConflictMask[pos] |= aMask;
}
}
return bandConflictMask;
}
// 递归回溯
function dfs(index, path, selectedMask, sum, count, bandConflictMask) {
if (index === n || count === k) {
if (sum > maxB) {
maxB = sum;
res = [...path];
}
return;
}
for (let i = index; i < n; i++) {
if ((selectedMask & bandConflictMask[i]) !== 0) {
continue;
}
path.push(i);
dfs(i + 1, path, selectedMask | (1 << i), sum + b[i], count + 1, bandConflictMask);
path.pop();
}
}
const f = input[idx++].split(" ");
const c = Number(input[idx++]);
const conflict = [];
for (let i = 0; i < c; i++) {
conflict.push(input[idx++].split(" "));
}
const bandConflictMask = getConflictMask(f, conflict);
dfs(0, [], 0, 0, 0, bandConflictMask);
console.log(maxB);
console.log(res.join(" "));
});
Go
go
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
var (
n, k int
b []int
// 最大带宽
maxB int
res []int
)
// 将字符串转换为小写
func toLowerCase(text string) string {
return strings.ToLower(text)
}
// 递归回溯
func dfs(index int, path []int, selectedMask int, sum int, count int, bandConflictMask []int) {
if index == n || count == k {
if sum > maxB {
maxB = sum
res = append([]int{}, path...)
}
return
}
for i := index; i < n; i++ {
if (selectedMask & bandConflictMask[i]) != 0 {
continue
}
path = append(path, i)
dfs(i+1, path, selectedMask|(1<<i), sum+b[i], count+1, bandConflictMask)
path = path[:len(path)-1]
}
}
func getConflictMask(f []string, conflict [][2]string) []int {
fPos := make(map[string][]int)
for i := 0; i < n; i++ {
low := toLowerCase(f[i])
fPos[low] = append(fPos[low], i)
}
// 每个频段拥有频段的mask表示形式
bandMask := make(map[string]int)
bandConflictMask := make([]int, n)
for name, band := range fPos {
mask := 0
for _, pos := range band {
mask |= 1 << pos
}
bandMask[name] = mask
// 处理每个频段
for _, pos := range band {
bandConflictMask[pos] = mask ^ (1 << pos)
}
}
// 处理冲突
for _, item := range conflict {
a := toLowerCase(item[0])
bb := toLowerCase(item[1])
aMask, ok1 := bandMask[a]
bMask, ok2 := bandMask[bb]
if !ok1 || !ok2 {
continue
}
for _, pos := range fPos[a] {
bandConflictMask[pos] |= bMask
}
for _, pos := range fPos[bb] {
bandConflictMask[pos] |= aMask
}
}
return bandConflictMask
}
func main() {
in := bufio.NewReader(os.Stdin)
fmt.Fscan(in, &n, &k)
b = make([]int, n)
for i := 0; i < n; i++ {
fmt.Fscan(in, &b[i])
}
f := make([]string, n)
for i := 0; i < n; i++ {
fmt.Fscan(in, &f[i])
}
var c int
fmt.Fscan(in, &c)
conflict := make([][2]string, c)
for i := 0; i < c; i++ {
fmt.Fscan(in, &conflict[i][0], &conflict[i][1])
}
bandConflictMask := getConflictMask(f, conflict)
dfs(0, []int{}, 0, 0, 0, bandConflictMask)
fmt.Println(maxB)
for i, v := range res {
if i > 0 {
fmt.Print(" ")
}
fmt.Print(v)
}
}