分析电网负载均衡
2026 华为OD机试真题 6月14日华为OD上机新系统考试真题 200 分题型
点击查看华为 OD 机试真题完整目录:2026最新华为OD机试新系统卷 + 双机位C卷 真题题库目录|全覆盖题库 + 逐点算法考点详解
题目描述
某电力公司管理N个变电站节点(编号0~N-1),节点间通过M条输电线路连接,相连节点属于同一供电区。定义供电区的不均衡度=区内最大负载与最小负载之差 ×节点数。请找出不均衡度最大的供电区,输出其不均衡度。若无有效供电区(节点数<2或M=0),输出-1。
输入描述
整型数组loads,长度为N,表示编号0~N-1的节点负载(MW); 二维整型数组edges,每行2个整数,表示该线路连接的两个节点编号,共M行。
约束:
1 ≤ N ≤ 100 0 ≤ M ≤ N×(N-1)/2 0 ≤ loads[i] ≤ 10000 0 ≤ edges[j][0], edges[j][1] ≤ N-1 edges[j][0] ≠ edges[j][1],无重复边
输出描述
整型,表示所有供电区中不均衡度的最大值。若无有效供电区,输出-1。
示例1
输入
[100,200,150,50,300],[[0,1],[1,2],[3,4]]
输出
500
说明
边(0,1)(1,2)将节点0,1,2连为供电区A,负载[100,200,150],不均衡度=(200-100)×3=300 边(3,4)将节点3,4连为供电区B,负载[50,300],不均衡度=(300-50)×2=500 供电区B不均衡度更大,输出500
示例2
输入
[80,90,80,90],[[0,1],[1,2],[2,3]]
输出
40
说明
4个节点连为1个供电区,不均衡度=(90-80)×4=40,输出40
示例3
输入
[100,200,300],[]
输出
-1
说明
每个节点独立,不构成有效供电区,输出-1
解题思路
核心思想
本题是一个 图的连通分量 问题,需要使用 并查集(Union-Find) 算法来找出所有供电区,然后计算每个供电区的不均衡度。
算法步骤:
- 初始化并查集,每个节点独立为一个集合
- 遍历所有边,将相连的节点合并到同一个集合
- 将同一集合的节点分组
- 对每个分组:
- 节点数 < 2 的跳过(不是有效供电区)
- 计算负载最大值和最小值
- 计算不均衡度 = (最大值 - 最小值) × 节点数
- 返回最大不均衡度,如果没有有效供电区返回 -1
并查集核心操作:
find(x):查找节点 x 所属集合的根节点(路径压缩优化)union(a, b):合并节点 a 和 b 所在的集合
复杂度分析
- 时间复杂度:O(N + M × α(N)),α 为 Ackermann 函数的反函数,近似常数
- 空间复杂度:O(N),存储父节点数组
Java
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String line = scanner.nextLine().trim();
int splitIndex = line.indexOf("],");
String loadsLine = line.substring(0, splitIndex + 1);
String edgesLine = line.substring(splitIndex + 2);
loadsLine = loadsLine.replace("[", "").replace("]", "");
String[] loadStrs = loadsLine.split(",");
int[] loads = new int[loadStrs.length];
for (int i = 0; i < loadStrs.length; i++) {
loads[i] = Integer.parseInt(loadStrs[i].trim());
}
int[][] edges;
if (edgesLine.equals("[]")) {
edges = new int[0][0];
} else {
edgesLine = edgesLine.replace("[[", "").replace("]]", "");
String[] edgePairs = edgesLine.split("],\\[");
edges = new int[edgePairs.length][2];
for (int i = 0; i < edgePairs.length; i++) {
String[] nodes = edgePairs[i].split(",");
edges[i][0] = Integer.parseInt(nodes[0].trim());
edges[i][1] = Integer.parseInt(nodes[1].trim());
}
}
int result = maxZoneImbalance(loads, edges);
System.out.println(result);
}
public static int maxZoneImbalance(int[] loads, int[][] edges) {
int nodeCount = loads.length;
if (edges.length == 0) {
return -1;
}
int[] parent = new int[nodeCount];
for (int i = 0; i < nodeCount; i++) {
parent[i] = i;
}
java.util.function.IntFunction<Integer> find = (x) -> {
while (parent[x] != x) {
parent[x] = parent[parent[x]];
x = parent[x];
}
return x;
};
java.util.function.BiConsumer<Integer, Integer> union = (a, b) -> {
int rootA = find.apply(a);
int rootB = find.apply(b);
if (rootA != rootB) {
parent[rootB] = rootA;
}
};
for (int[] edge : edges) {
union.accept(edge[0], edge[1]);
}
Map<Integer, List<Integer>> groups = new HashMap<>();
for (int i = 0; i < nodeCount; i++) {
int root = find.apply(i);
groups.computeIfAbsent(root, k -> new ArrayList<>()).add(i);
}
int answer = -1;
for (List<Integer> nodes : groups.values()) {
if (nodes.size() < 2) {
continue;
}
int maxLoad = Integer.MIN_VALUE;
int minLoad = Integer.MAX_VALUE;
for (int node : nodes) {
maxLoad = Math.max(maxLoad, loads[node]);
minLoad = Math.min(minLoad, loads[node]);
}
int imbalance = (maxLoad - minLoad) * nodes.size();
answer = Math.max(answer, imbalance);
}
return answer;
}
}
Python
def max_zone_imbalance(loads, edges):
n = len(loads)
if not edges:
return -1
parent = list(range(n))
def find(x):
while parent[x] != x:
parent[x] = parent[parent[x]]
x = parent[x]
return x
def union(a, b):
ra = find(a)
rb = find(b)
if ra != rb:
parent[rb] = ra
for u, v in edges:
union(u, v)
groups = {}
for i in range(n):
root = find(i)
groups.setdefault(root, []).append(i)
ans = -1
for nodes in groups.values():
if len(nodes) < 2:
continue
max_load = max(loads[i] for i in nodes)
min_load = min(loads[i] for i in nodes)
imbalance = (max_load - min_load) * len(nodes)
if imbalance > ans:
ans = imbalance
return ans
import sys
line = sys.stdin.readline().strip()
if not line:
sys.exit()
idx = line.index("],")
loads_part = line[:idx + 1]
edges_part = line[idx + 2:]
loads_part = loads_part.strip("[]")
loads = [int(x.strip()) for x in loads_part.split(",") if x.strip()]
if edges_part.strip() == "[]":
edges = []
else:
inner = edges_part.strip("[]")
pair_strs = inner.split("],[")
edges = []
for pair in pair_strs:
a, b = pair.split(",")
edges.append([int(a.strip()), int(b.strip())])
print(max_zone_imbalance(loads, edges))
JavaScript
function maxZoneImbalance(loads, edges) {
const n = loads.length;
if (edges.length === 0) return -1;
const parent = Array.from({ length: n }, (_, i) => i);
function find(x) {
while (parent[x] !== x) {
parent[x] = parent[parent[x]];
x = parent[x];
}
return x;
}
for (const [u, v] of edges) {
const ru = find(u);
const rv = find(v);
if (ru !== rv) parent[rv] = ru;
}
const groups = new Map();
for (let i = 0; i < n; i++) {
const r = find(i);
if (!groups.has(r)) groups.set(r, []);
groups.get(r).push(i);
}
let ans = -1;
for (const nodes of groups.values()) {
if (nodes.length < 2) continue;
let maxLoad = -Infinity;
let minLoad = Infinity;
for (const node of nodes) {
const v = loads[node];
if (v > maxLoad) maxLoad = v;
if (v < minLoad) minLoad = v;
}
const imbalance = (maxLoad - minLoad) * nodes.length;
if (imbalance > ans) ans = imbalance;
}
return ans;
}
const readline = require('readline');
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
rl.on('line', (line) => {
line = line.trim();
const idx = line.indexOf('],');
const loadsPart = line.substring(0, idx + 1);
const edgesPart = line.substring(idx + 2);
const loadsStr = loadsPart.replace(/[\[\]]/g, '');
const loads = loadsStr.split(',').map(s => parseInt(s.trim())).filter(x => !isNaN(x));
let edges;
if (edgesPart.trim() === '[]') {
edges = [];
} else {
const inner = edgesPart.replace(/^\[\[|\]\]$/g, '');
const pairStrs = inner.split('],[');
edges = pairStrs.map(pair => pair.split(',').map(n => parseInt(n.trim())));
}
console.log(maxZoneImbalance(loads, edges));
rl.close();
});
C++
#include <bits/stdc++.h>
using namespace std;
class UnionFind {
private:
vector<int> parent;
public:
UnionFind(int n) {
parent.resize(n);
for (int i = 0; i < n; i++) {
parent[i] = i;
}
}
int find(int x) {
while (parent[x] != x) {
parent[x] = parent[parent[x]];
x = parent[x];
}
return x;
}
void unite(int a, int b) {
int rootA = find(a);
int rootB = find(b);
if (rootA != rootB) {
parent[rootB] = rootA;
}
}
};
int maxZoneImbalance(vector<int>& loads, vector<vector<int>>& edges) {
int n = loads.size();
if (edges.empty()) {
return -1;
}
UnionFind uf(n);
for (auto& edge : edges) {
uf.unite(edge[0], edge[1]);
}
unordered_map<int, vector<int>> groups;
for (int i = 0; i < n; i++) {
int root = uf.find(i);
groups[root].push_back(i);
}
int ans = -1;
for (auto& item : groups) {
vector<int>& nodes = item.second;
if (nodes.size() < 2) {
continue;
}
int maxLoad = INT_MIN;
int minLoad = INT_MAX;
for (int node : nodes) {
maxLoad = max(maxLoad, loads[node]);
minLoad = min(minLoad, loads[node]);
}
int imbalance = (maxLoad - minLoad) * nodes.size();
ans = max(ans, imbalance);
}
return ans;
}
int main() {
string line;
getline(cin, line);
vector<int> loads;
vector<vector<int>> edges;
int splitIndex = line.find("],");
string loadsLine = line.substr(0, splitIndex + 1);
string edgesLine = line.substr(splitIndex + 2);
for (int i = 0; i < loadsLine.size(); i++) {
if (isdigit(loadsLine[i])) {
int num = 0;
while (i < loadsLine.size() && isdigit(loadsLine[i])) {
num = num * 10 + loadsLine[i] - '0';
i++;
}
loads.push_back(num);
}
}
if (edgesLine != "[]") {
for (int i = 0; i < edgesLine.size(); i++) {
if (isdigit(edgesLine[i])) {
int a = 0;
while (i < edgesLine.size() && isdigit(edgesLine[i])) {
a = a * 10 + edgesLine[i] - '0';
i++;
}
while (i < edgesLine.size() && !isdigit(edgesLine[i])) {
i++;
}
int b = 0;
while (i < edgesLine.size() && isdigit(edgesLine[i])) {
b = b * 10 + edgesLine[i] - '0';
i++;
}
edges.push_back({a, b});
}
}
}
cout << maxZoneImbalance(loads, edges) << endl;
return 0;
}
Go
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func maxZoneImbalance(loads []int, edges [][]int) int {
n := len(loads)
if len(edges) == 0 {
return -1
}
parent := make([]int, n)
for i := 0; i < n; i++ {
parent[i] = i
}
var find func(int) int
find = func(x int) int {
for parent[x] != x {
parent[x] = parent[parent[x]]
x = parent[x]
}
return x
}
union := func(a, b int) {
ra := find(a)
rb := find(b)
if ra != rb {
parent[rb] = ra
}
}
for _, e := range edges {
union(e[0], e[1])
}
groups := make(map[int][]int)
for i := 0; i < n; i++ {
r := find(i)
groups[r] = append(groups[r], i)
}
ans := -1
for _, nodes := range groups {
if len(nodes) < 2 {
continue
}
maxLoad := -1 << 31
minLoad := 1<<31 - 1
for _, node := range nodes {
if loads[node] > maxLoad {
maxLoad = loads[node]
}
if loads[node] < minLoad {
minLoad = loads[node]
}
}
imbalance := (maxLoad - minLoad) * len(nodes)
if imbalance > ans {
ans = imbalance
}
}
return ans
}
func main() {
reader := bufio.NewReader(os.Stdin)
line, _ := reader.ReadString('\n')
line = strings.TrimSpace(line)
idx := strings.Index(line, "],")
if idx == -1 {
return
}
loadsPart := line[:idx+1]
edgesPart := line[idx+2:]
loadsStr := strings.Trim(loadsPart, "[]")
loadTokens := strings.Split(loadsStr, ",")
loads := make([]int, 0)
for _, t := range loadTokens {
t = strings.TrimSpace(t)
if t == "" {
continue
}
v, _ := strconv.Atoi(t)
loads = append(loads, v)
}
var edges [][]int
edgesPart = strings.TrimSpace(edgesPart)
if edgesPart == "[]" {
edges = [][]int{}
} else {
inner := strings.TrimPrefix(edgesPart, "[[")
inner = strings.TrimSuffix(inner, "]]")
pairs := strings.Split(inner, "],[")
for _, p := range pairs {
nums := strings.Split(p, ",")
if len(nums) == 2 {
a, _ := strconv.Atoi(strings.TrimSpace(nums[0]))
b, _ := strconv.Atoi(strings.TrimSpace(nums[1]))
edges = append(edges, []int{a, b})
}
}
}
fmt.Println(maxZoneImbalance(loads, edges))
}
C语言
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
int find(int* parent, int x) {
while (parent[x] != x) {
parent[x] = parent[parent[x]];
x = parent[x];
}
return x;
}
void unionSet(int* parent, int a, int b) {
int ra = find(parent, a);
int rb = find(parent, b);
if (ra != rb) parent[rb] = ra;
}
int maxZoneImbalance(int* loads, int n, int edges[][2], int m) {
if (m == 0) return -1;
int* parent = (int*)malloc(n * sizeof(int));
for (int i = 0; i < n; i++) parent[i] = i;
for (int i = 0; i < m; i++) {
unionSet(parent, edges[i][0], edges[i][1]);
}
int* groupSize = (int*)calloc(n, sizeof(int));
int* groupMin = (int*)malloc(n * sizeof(int));
int* groupMax = (int*)malloc(n * sizeof(int));
int ans = -1;
for (int i = 0; i < n; i++) {
int r = find(parent, i);
if (groupSize[r] == 0) {
groupMin[r] = groupMax[r] = loads[i];
} else {
if (loads[i] < groupMin[r]) groupMin[r] = loads[i];
if (loads[i] > groupMax[r]) groupMax[r] = loads[i];
}
groupSize[r]++;
}
for (int i = 0; i < n; i++) {
if (groupSize[i] >= 2) {
int imbalance = (groupMax[i] - groupMin[i]) * groupSize[i];
if (imbalance > ans) ans = imbalance;
}
}
free(parent);
free(groupSize);
free(groupMin);
free(groupMax);
return ans;
}
int main() {
char line[100000];
scanf("%[^\n]", line);
char* idx = strstr(line, "],");
if (!idx) return 1;
int splitPos = idx - line;
char loadsPart[50000];
strncpy(loadsPart, line, splitPos + 1);
loadsPart[splitPos + 1] = '\0';
char* edgesPart = line + splitPos + 2;
int* loads = (int*)malloc(100000 * sizeof(int));
int loadCount = 0;
char* lp = loadsPart;
while (*lp == '[') lp++;
char* end = strchr(lp, ']');
if (end) *end = '\0';
char* token = strtok(lp, ",");
while (token) {
while (*token == ' ') token++;
loads[loadCount++] = atoi(token);
token = strtok(NULL, ",");
}
int edges[100000][2];
int edgeCount = 0;
while (*edgesPart == ' ') edgesPart++;
if (strcmp(edgesPart, "[]") != 0) {
char* ep = edgesPart;
while (*ep == '[') ep++;
char buff[100000];
strcpy(buff, ep);
int len = strlen(buff);
if (len > 0 && buff[len - 1] == ']') buff[--len] = '\0';
char* p = buff;
while (*p) {
char* next = strstr(p, "],[");
if (next) {
*next = '\0';
int a, b;
sscanf(p, "%d,%d", &a, &b);
edges[edgeCount][0] = a;
edges[edgeCount][1] = b;
edgeCount++;
p = next + 3;
} else {
int a, b;
sscanf(p, "%d,%d", &a, &b);
edges[edgeCount][0] = a;
edges[edgeCount][1] = b;
edgeCount++;
break;
}
}
}
int result = maxZoneImbalance(loads, loadCount, edges, edgeCount);
printf("%d\n", result);
free(loads);
return 0;
}
完整用例
用例1
[100,200,150,50,300],[[0,1],[1,2],[3,4]]
用例2
[80,90,80,90],[[0,1],[1,2],[2,3]]
用例3
[100,200,300],[]
用例4
[50,100,150],[[0,1]]
用例5
[10,20,30,40],[[0,1],[2,3]]
用例6
[1,1,1,1],[[0,1],[1,2],[2,3]]
用例7
[0,1000],[[0,1]]
用例8
[10,20,30,40,50],[[0,1],[1,2],[2,3],[3,4]]
用例9
[5,5],[[0,1]]
用例10
[100],[]
文章目录


476

被折叠的 条评论
为什么被折叠?



