华为非AI方向笔试真题 8月19号 【流量均衡控制】

流量均衡控制

华为笔试真题 8月19号 非AI方向第三题 300分题型

题目内容

某厂商生产的交换机需要对用户的信息进行处理:按照信息的类别划分优先级,并为每种流量类型设置权重,用于在同优先级的场景下,让设备优先处理权重更高的消息。具体分类如下:

流量类型 权重
媒体流 20
信令流 15
内部管理流量 5
其他流量 0

假设某台交换机当前由 2 个端口组成一组,共同负责消息的接收与处理。这两个端口需要处理的所有消息的权重构成数组 arr。请问是否存在一种消息分发方式,使得每个端口处理的消息的权重均值相同,即能否将权重数组拆分为两个均值相等的子数组?本题只要求判断是否存在这样的分组,无需考虑多种分组方式。

输入描述

输入为一个字符串,每个数字代表一条消息的权重。权重的取值只能来自上表,即 20、15、5、020、15、5、020、15、5、0,不存在其他值。各权重之间用空格分隔,例如:

复制代码
5 5 5 20 15 15 5 5 20 15 15 5 5 20 15 15 15

数组大小(即消息数量)满足 1≤n≤1001 \le n \le 1001≤n≤100。

输出描述

第一行:输出 011 表示存在一种消息分发方式,使得各端口处理的消息权重均值相同;0 表示不存在这样的分发方式。

第二行:若第一行输出为 1,则输出其中一个子数组的元素和;若两个子数组的元素和不同,则输出较小的那一个。若第一行输出为 0,则本行无需输出。

样例 1

输入

复制代码
15 20

输出

复制代码
0

说明

不存在任何划分方式,能使两个子数组的均值相同,因此输出 0。

样例 2

输入

复制代码
5 20 15 15 5 5 5 20 5 5 15 15

输出

复制代码
1
65

说明

每个端口处理的消息权重可以取 5 5 5 20 15 15,此时两个端口处理的消息权重均值一致,均为 10.833310.833310.8333。

样例 3

输入

复制代码
15 20 5 20

输出

复制代码
1
15

说明

可以划分为两个组,均值均为 151515:

  • 第一个组:151515,子数组元素和为 151515
  • 第二个组:20 5 2020\ 5\ 2020 5 20,子数组元素和为 454545

题解

思路

思路:动态规划

  1. 共有n个元素,总权重和为T,存在合法两个子数组的平均值相等。必定满足以下条件
    • 其中一个子数组个数为cnt, 元素和为sum
    • sum / cnt = (T - sum) / (n - cnt) => sum * n = cnt * T
  2. 基于1的分析使用动态规划定义dp[cnt][sum]表示是否可以选出 cnt 个元素,使它们的和为 sum
  3. 然后使用01背包算法推导出所有存在的cnt,sum状态情况。
  4. 然后判断遍历dp数组,在dp[cnt][sum]为true的情况,看是否满足sum / cnt = (T - sum) / (n - cnt) => sum * n = cnt * T的情况,满足输出对应结果即可。

C++

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    vector<int> arr;
    int x;
    int total = 0;
    while (cin >> x) {
        arr.push_back(x / 5);
        total += x / 5;
    }
    int n = arr.size();
    // 无法形成合法方案
    if (n < 2) {
        cout << 0;
        return 0;
    }
    // dp[cnt][sum]:是否可以选出 cnt 个元素,使元素和为 sum
    vector<vector<bool>> dp(n + 1, vector<bool>(total + 1, false));
    dp[0][0] = true;
    for (int x : arr) {
        // 0/1 背包,必须从大到小枚举
        for (int cnt = n; cnt >= 1; cnt--) {
            for (int sum = total; sum >= x; sum--) {
                dp[cnt][sum] = dp[cnt][sum] | dp[cnt - 1][sum - x];
            }
        }
    }    
    
    for (int cnt = 1; cnt < n; cnt++) {
        for (int sum = 0; sum <= total; sum++) {
            if (!dp[cnt][sum]) {
                continue;
            }
            // 两个子集平均值相同
            // sum / cnt = (total - sum) / (n - cnt)  => sum * n == cnt * total
            if (sum * n == cnt * total) {
                int otherSum = total - sum;
                cout << 1 << endl;
                cout << min(sum, otherSum) * 5 << endl;
                return 0;
            }
        }
    }
    cout << 0 << '\n';
    return 0;
}

java

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

public class Main {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        StringBuilder sb = new StringBuilder();
        String line;
        while ((line = br.readLine()) != null) {
            sb.append(line).append(" ");
        }

        String[] input = sb.toString().trim().split("\\s+");

        List<Integer> arr = new ArrayList<>();
        int total = 0;

        for (String str : input) {
            int x = Integer.parseInt(str);
            arr.add(x / 5);
            total += x / 5;
        }

        int n = arr.size();

        // 无法形成合法方案
        if (n < 2) {
            System.out.println(0);
            return;
        }

        // dp[cnt][sum]:是否可以选出 cnt 个元素,使元素和为 sum
        boolean[][] dp = new boolean[n + 1][total + 1];
        dp[0][0] = true;

        for (int x : arr) {
            // 0/1 背包,必须从大到小枚举
            for (int cnt = n; cnt >= 1; cnt--) {
                for (int sum = total; sum >= x; sum--) {
                    dp[cnt][sum] = dp[cnt][sum] || dp[cnt - 1][sum - x];
                }
            }
        }

        for (int cnt = 1; cnt < n; cnt++) {
            for (int sum = 0; sum <= total; sum++) {
                if (!dp[cnt][sum]) {
                    continue;
                }

                // 两个子集平均值相同
                // sum / cnt = (total - sum) / (n - cnt)  => sum * n == cnt * total
                if (sum * n == cnt * total) {
                    int otherSum = total - sum;

                    System.out.println(1);
                    System.out.println(Math.min(sum, otherSum) * 5);
                    return;
                }
            }
        }

        System.out.println(0);
    }
}

python

python 复制代码
import sys

data = sys.stdin.read().split()

arr = []
total = 0

for value in data:
    x = int(value)
    arr.append(x // 5)
    total += x // 5

n = len(arr)

# 无法形成合法方案
if n < 2:
    print(0)
    sys.exit()

# dp[cnt][sum]:是否可以选出 cnt 个元素,使元素和为 sum
dp = [[False] * (total + 1) for _ in range(n + 1)]
dp[0][0] = True

for x in arr:
    # 0/1 背包,必须从大到小枚举
    for cnt in range(n, 0, -1):
        for sum_value in range(total, x - 1, -1):
            dp[cnt][sum_value] = (
                dp[cnt][sum_value] or dp[cnt - 1][sum_value - x]
            )

for cnt in range(1, n):
    for sum_value in range(total + 1):
        if not dp[cnt][sum_value]:
            continue

        # 两个子集平均值相同
        # sum / cnt = (total - sum) / (n - cnt)  => sum * n == cnt * total
        if sum_value * n == cnt * total:
            other_sum = total - sum_value

            print(1)
            print(min(sum_value, other_sum) * 5)
            sys.exit()

print(0)

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', () => {
    const data = input.join(' ').trim().split(/\s+/);

    const arr = [];
    let total = 0;

    for (const value of data) {
        const x = Number(value);
        arr.push(Math.floor(x / 5));
        total += Math.floor(x / 5);
    }

    const n = arr.length;

    // 无法形成合法方案
    if (n < 2) {
        console.log(0);
        return;
    }

    // dp[cnt][sum]:是否可以选出 cnt 个元素,使元素和为 sum
    const dp = Array.from(
        { length: n + 1 },
        () => new Array(total + 1).fill(false)
    );

    dp[0][0] = true;

    for (const x of arr) {
        // 0/1 背包,必须从大到小枚举
        for (let cnt = n; cnt >= 1; cnt--) {
            for (let sum = total; sum >= x; sum--) {
                dp[cnt][sum] =
                    dp[cnt][sum] || dp[cnt - 1][sum - x];
            }
        }
    }

    for (let cnt = 1; cnt < n; cnt++) {
        for (let sum = 0; sum <= total; sum++) {
            if (!dp[cnt][sum]) {
                continue;
            }

            // 两个子集平均值相同
            // sum / cnt = (total - sum) / (n - cnt)  => sum * n == cnt * total
            if (sum * n === cnt * total) {
                const otherSum = total - sum;

                console.log(1);
                console.log(Math.min(sum, otherSum) * 5);
                return;
            }
        }
    }

    console.log(0);
});

Go

go 复制代码
package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	in := bufio.NewReader(os.Stdin)
	out := bufio.NewWriter(os.Stdout)
	defer out.Flush()

	arr := make([]int, 0)
	total := 0

	var x int

	for {
		_, err := fmt.Fscan(in, &x)
		if err != nil {
			break
		}

		arr = append(arr, x/5)
		total += x / 5
	}

	n := len(arr)

	// 无法形成合法方案
	if n < 2 {
		fmt.Fprintln(out, 0)
		return
	}

	// dp[cnt][sum]:是否可以选出 cnt 个元素,使元素和为 sum
	dp := make([][]bool, n+1)
	for i := 0; i <= n; i++ {
		dp[i] = make([]bool, total+1)
	}

	dp[0][0] = true

	for _, x := range arr {
		// 0/1 背包,必须从大到小枚举
		for cnt := n; cnt >= 1; cnt-- {
			for sum := total; sum >= x; sum-- {
				dp[cnt][sum] = dp[cnt][sum] || dp[cnt-1][sum-x]
			}
		}
	}

	for cnt := 1; cnt < n; cnt++ {
		for sum := 0; sum <= total; sum++ {
			if !dp[cnt][sum] {
				continue
			}

			// 两个子集平均值相同
			// sum / cnt = (total - sum) / (n - cnt)  => sum * n == cnt * total
			if sum*n == cnt*total {
				otherSum := total - sum

				fmt.Fprintln(out, 1)

				if sum < otherSum {
					fmt.Fprintln(out, sum*5)
				} else {
					fmt.Fprintln(out, otherSum*5)
				}

				return
			}
		}
	}

	fmt.Fprintln(out, 0)
}
相关推荐
OH_TPC12 小时前
HarmonyOS APP开发---“启动秀“应用引导页App,需要用到这个库
华为·harmonyos·鸿蒙
lilian23313 小时前
Harmony os 技术实战|拼豆制图43:压缩字符矩阵上线前如何拦住错位图纸
开发语言·前端·华为·矩阵·harmonyos
2501_9197490320 小时前
华为鸿蒙免费戒咖啡APP—小羊戒咖
华为·harmonyos·鸿蒙
2501_919749031 天前
华为鸿蒙免费戒烟APP—小羊戒烟
华为·harmonyos·鸿蒙
math_hongfan1 天前
鸿蒙ArkTS手势交互:拖拽、缩放、旋转与组合手势
学习·华为·交互·harmonyos·鸿蒙
zzz海羊1 天前
2026全平台移动办公远控助手横测:从鸿蒙到工作站,ToDesk、向日葵、TeamViewer、AnyDesk谁更适配?
人工智能·华为·agent·harmonyos·teamviewer
less_121381 天前
HarmonyOS WPS Open SDK:对接文档阅读路径与联调自查
华为·harmonyos·wps
lilian2331 天前
Harmony os 技术实战|拼豆制图48:把个人页字符串路由改成可穷尽的类型协议
前端·华为·harmonyos
小雨青年1 天前
【HarmonyOS 7 悬浮页签深度实战】03 barFloatingStyle 的宽度、底部间距与遮罩如何配置
华为·harmonyos