第七届全球校园人工智能算法精英大赛-算法巅峰赛产业命题赛第3赛季优化题--碳中和

前言

"全球校园人工智能算法精英大赛"是江苏省人工智能学会举办的面向全球具有正式学籍的全日制高等院校及以上在校学生举办的算法竞赛。其中的算法巅峰赛属于产业命题赛道,这是第3赛季,这次优化题的主题是 "碳中和"。


AIC·算法巅峰赛赛题及竞赛规则


题目描述

给你 N 个任务 和 M 台服务器,需要决定:

  • 哪些任务要执行
  • 每个执行的任务分配到哪台服务器

核心约束

  1. 功耗约束
    每台服务器的实际总功耗 ≤ 该服务器的功耗上限
  2. 热量约束
    每台服务器的实际承受总热量 ≤ 该服务器的热量阈值
  3. 热量传导规则
    服务器排成一排,相邻服务器会互相传导热量:

怎么理解热量约束和热量传达规则

服务器 p 承受的热量 = 服务器 p 任务的热量总和 + 左邻热量和 × K + 右邻热量和 × K 服务器 p 承受的热量 = 服务器p 任务的热量总和 + 左邻热量和 × K + 右邻热量和 × K 服务器p承受的热量=服务器p任务的热量总和+左邻热量和×K+右邻热量和×K

注: 左右两侧服务器的特殊情况,非环。

核心目标

在满足所有限制条件下,最大化总收益。

输入数据

第一行

复制代码
N M K

N:任务数量(1-4000)

M:服务器数量(1-800)

K:热量传导系数(0.0-1.0)

任务数据(N行,每行3个数字)

复制代码
收益 功耗 热量

服务器数据(M行,每行2个数字)

复制代码
功耗上限 热量阈值

输出格式

输出 N 个数字,用空格分隔:

复制代码
a_1, a_2, a_3, ..., a_n

a i ∈ [ 0 , m ] a_i \in [0, m] ai∈[0,m] 其中0: 该任务i不执行, 1-M: 该任务 i分配到几号服务器

sample

输入

复制代码
3 2 1.0
10 3 4
8 4 3
5 2 2
5 7
7 8

输出

复制代码
1 2 0

解释

复制代码
有 3 个任务,2 台服务器,K=1.0(100%传导)
服务器1:最多用5功耗,承受7热量
服务器2:最多用7功耗,承受8热量

任务1(功耗3,热量4)→ 服务器1
任务2(功耗4,热量3)→ 服务器2
任务3不执行

检查约束:
服务器1:功耗3 ≤ 5 ✅,热量4 ≤ 7 ✅
服务器2:功耗4 ≤ 7 ✅,热量3 ≤ 8 ✅

考虑传导:
服务器1总热量:自己4 + 邻居传导3×1.0 = 7(刚好等于阈值7)✅
服务器2总热量:自己3 + 邻居传导4×1.0 = 7 ≤ 8 ✅
总收益:10 + 8 = 18 ✅

思路分析

该问题属于带约束的多维度资源分配优化问题,是组合优化问题。

该问题可以视为 二维费用的 0-1 多重背包的变形问题。


高分思路

贪心策略

  1. 任务task按照收益从高到低排序
  2. 按需为每个 task寻找第一个满足约束限制的服务器 server 节点,进行分配
python3 复制代码
# task按收益从高到低排序
tasks.sort(key=lambda x: -x.val)

# 遍历每个任务
for task in tasks:
	for server in servers:
		# 如果该服务器,添加该任务后,依旧满足约束
		if server.satisfy(task):
			# 该 task 被赋予给 该 server
			task -> server 
			break

就这么一个简单的思路,最后分数为 400+,赛时前 15 名。


多策略混合

保留原先的贪心策略主框架,做一些策略抽象

python3 复制代码
sort_stragety  #排序策略
choice_strategy # 挑选策略

# task按 策略 sort_strategy 排序
tasks.sort(key=sort_stragety)

# 遍历每个任务
for task in tasks:
	candidate_list = []
	for server in servers:
		# 如果该服务器,添加该任务后,依旧满足约束
		if server.satisfy(task):
			candidate_list.append(server)
	
	# 如果存在候选服务器列表
	if candidate_list:
	    # 按挑选策略,选择具体的svr
		svr = choice_strategy(candidate_list)
		task -> svr # 把 task 赋予某个 server 执行	

这里抽象了 2 个策略,sort_stragety/choice_strategy

任务的排序策略

  • 按收益值从高到低 排序
  • 按收益/功耗 比值,从高到低 排序
  • 按收益/热度 比值,从高到低 排序
  • 按收益/功耗热度的比值,从高到低 排序

服务器的挑选策略

  • FF(First-Fit)
    选择第一个满足要求服务器
  • BF(Best-Fit)
    按最优策略,比如定义 加权 功耗利用率 + 热量利用率的函数,越高越好
  • RF(Random-Fit)
    随机挑选任一个满足要求的服务器
  • 概率放弃
    按一定概率放弃此次选择任务和服务器配对,否则采用上述几种策略挑选

而任务的排序策略+服务器的挑选策略,做一个组合搭配。

这样的混合策略得分为 440+,赛时前三。


模拟退火

模拟退火也可以做这题,但操作因子设计就很复杂,不太好实现。

这边以最简单的任务重分配操作因子 为例(纯展示)

python 复制代码
import math, random
from math import inf

class Task(object):
    def __init__(self, value, power, heat):
        self.value = value
        self.power = power
        self.heat = heat

class Server(object):
    def __init__(self, p_limit, h_limit):
        self.p_limit = p_limit
        self.h_limit = h_limit


N, M, K = input().split()
N, M, K = int(N), int(M), float(K)

tasks = []
for _ in range(N):
    value, power, heat = list(map(int, input().split()))
    tasks.append(Task(value, power, heat))

servers = []
for _ in range(M):
    p_limit, h_limit = list(map(int, input().split()))
    servers.append(Server(p_limit, h_limit))


def fitness(assigns):
    ans = 0
    tmp_power = [0] * M
    tmp_heat = [0] * M
    for i in range(N):
        id = assigns[i]
        if id >= 0:
            tmp_power[id] += tasks[i].power
            tmp_heat[id] += tasks[i].heat
            ans += tasks[i].value
    # check
    for i in range(M):
        if tmp_power[i] > servers[i].p_limit:
            return -inf
        heat = tmp_heat[i]
        if i > 0: heat += tmp_heat[i - 1] * K
        if i + 1 < M: heat += tmp_heat[i + 1] * K
        if heat > servers[i].h_limit:
            return -inf

    return ans

assigns = [-1] * N
current_score = 0

best_score = 0
best_ans = assigns[:]

a = 0.999
T = 1000
while T > 1e-6:

    # reassign
    idx = random.randint(0, N - 1)
    old = assigns[idx]
    assigns[idx] = random.randint(-1, M - 1)  #

    score = fitness(assigns)
    if score == -inf:
        # 不合法的方案立马拒绝
        assigns[idx] = old
        T = T * a
        continue

    delta = score - current_score
    if delta > 0 or random.random() < math.exp(delta / T):
        # accept
        current_score = score
        if current_score > best_score:
            best_score = current_score
            best_ans = assigns[:]
    else:
        # reject
        assigns[idx] = old

    T = T * a

print (*[v + 1 for v in best_ans])

这个大概可以拿 300+分,有点意外

这个操作因子,效率太低了,间接反映了比赛实际的数据相对较弱,容易得分。

具体更有效率的操作因子,可具体问问 AI 大模型。


写在最后

相关推荐
良木生香2 小时前
【数据结构-初阶】详解线性表(2)---单链表
c语言·数据结构·算法
jinxinyuuuus2 小时前
AI 硬件助手:LLM的比较推理与自动化决策理由生成
人工智能·自动化
牛三金2 小时前
魔改-隐语PSI通信,支持外部通信自定义
服务器·前端·算法
菜鸟233号2 小时前
力扣106 从中序与后序遍历序列构造二叉树 java实现
java·算法·leetcode
智界前沿2 小时前
AI数字人公司推荐,集之互动如何在医疗、政务、汽车等关键领域打造“标杆案例”
人工智能·汽车·政务
水如烟2 小时前
孤能子视角:“人本关系线“耦合––焦耳、功率、效率、个人学习
人工智能
Donald_wsn2 小时前
牛客 栈和排序 C++
数据结构·c++·算法
FIT2CLOUD飞致云2 小时前
重要发布丨新增支持工作流知识库和数据源工具,MaxKB开源企业级智能体平台v2.4.0版本发布
人工智能·ai·开源·1panel·maxkb
The Straggling Crow2 小时前
RAGFlow
人工智能