2026年电工杯数学建模B题嵌入式社区养老服务站的建设与优化问题求解全过程论文及程序

2026年电工杯数学建模

B题 嵌入式社区养老服务站的建设与优化问题

原题再现:

  3 月7日,十四届全国人大四次会议在北京举行民生主题记者会。民政部部长陆治原指出,我国已初步建成覆盖城乡的养老服务"一张网",......,在城市建设嵌入式社区养老服务中心,在农村建设邻里互助点、农村幸福院。越来越多的老年人在家门口,甚至在家里就能够获得方便可及的养老服务。陆治原表示,未来五年持续建设县级综合养老服务管理平台,拓展区域养老服务中心功能,因地制宜扩大村和社区养老服务设施站点的覆盖面,争取到"十五五"末基本建成县乡村三级养老服务网络。
  某城市成熟街道下辖10个连片小区,当地政府计划建设嵌入式社区养老服务站,为老龄人群提供助餐、日间照料、上门护理、康复理疗、助浴、紧急救助等一系列为民服务项目,解决老龄人群面临的困难。附件1-6中给出该区域有关数据:
  附件1.小区基础数据:(1)人口与老人结构;(2)转移概率。
  附件2. 服务需求数据:(1)每位老人月均服务需求次数;(2)服务营收及支出;(3)月服务消费上限。
  附件3. 服务站建设与运营成本。
  附件4. 小区间距离矩阵(单位:米)。
  附件5. 满意度评分规则。
  假设老人只选择满意度最高的服务站;服务站服务能力与规模成正比;五年内人口结构与失能率相对平稳变化;当地工资、物价与补贴政策保持稳定。请根据所给数据,解决以下几个问题:
  问题1:未来五年老人数量与服务需求量预测
  1.1 假设老年人年均自然死亡率为5%,且年均新增老年人(刚满60岁)占当前总老年人口的 7%,失能老人无法恢复为自理或半失能老人,半失能老人有一定概率转移成为失能老人,但不会自然恢复为自理老人,自理老人有一定概率转移成为半失能老人。根据附件1中每个小区老人的当前数量及转移概率,建立未来5年的老人数量递推预测模型,预测第1年至第5年末每个小区各类老人的数量。
  1.2 根据1.1 的预测结果及附件2中的数据,预测第5年末每个小区对各项服务(助餐、日间照料、上门护理、康复理疗、助浴、紧急救助)的理论月需求次数(分自理、半失能、失能,单位:次/月,尽量取整)(注:此处为理论需求总量,未考虑消费能力约束)。
  1.3 根据附件1及附件2所给数据及消费约束,预测第5年末每个小区各类老人月均服务需求次数(单位:次/月,尽量取整)。
  问题2:服务站选址与规模优化
基于问题1预测的第5年末每个小区老人数量与消费约束的服务需求量,考虑服务站选址与规模优化问题,相关要求说明如下: 服务站规模:小型(服务≤1000人次/日)、中型(服务≤2000人次/日)、大型(服务≤3000人次/日),对应建设成本与运营成本见附件3; 服务站可选位置:10 个小区中的任意若干个(仅限小区内部,小区间距离见附件4); 服务半径要求:有效服务半径≤1000米;超出距离不产生有效服务需求。 服务覆盖率:至少享受一项养老服务的老年人数占老年总人口的比例。 服务满意度:根据附件5的评分规则(距离、服务响应、价格)计算,取值范围0.6~1。 实际有效服务人次:等于理论需求人次×服务满意度
  2.1 假设总建设预算不超过120万元,服务站建设需满足上述要求,建立优化模型,确定区域内需建设服务站数量、位置、规模,使得服务覆盖率和服务满意度尽可能高。
  2.2 设计求解算法,说明算法的主要步骤,并分析算法的时间复杂度。
  2.3 给出最优的站点数量、位置(哪个小区)、规模(大/中/小)及每个站点覆盖的小区,计算此时每个服务站预计年度利润、服务覆盖率和每个小区老人满意度,指出至少3点模型的局限性,并提出至少一种改进方向。
  问题3. 服务定价与政府补贴优化
  为降低老人负担,政府决定对服务站给予补贴,以降低服务价格,相关情况说明如下: 政府补贴:除紧急救助外,其他服务按实际有效服务人次补贴:2元/人次;单个服务站每日补贴最高限额(小型:1000元;中型:1800元;大型:2600元);紧急救助公益免费,不计补贴,仅核算直接支出。 利润率:养老机构需保本微利,利润率≤8%; "利润率=(服务总利润+政府补贴−年运营成本总额)/年运营成本总额×100%"
  3.1 假设服务站的选址和规模已按问题2的最优方案确定,本问题允许每个服务站自主定价,以"最大化老人满意度"为目标,建立优化模型,在考虑政府补贴及利润率要求情况下,确定各项服务的最优定价(元/次)。
  3.2 求解上述模型,给出最优定价,并计算此时每个服务站预计年度利润及利润率,同时计算此时每个小区老人满意度得分,并单独列出其中的"价格满意度得分"。
  3.3 分析定价与补贴对不同类型老人(自理、半失能、失能)服务可及性的影响。(可及性指的是老年人能否在经济上、地理上、信息上等维度方便地获得所需服务)
  问题4:灵敏度分析与方案比较
  4.1 分别改变以下参数,重新求解问题2和问题3,并进行比较。 老人增长率:将60+老人年增长率调整为8%;自理 → 半失能转移概率调整为5.5%,半失能 → 失能转移概率调整为9.5%; 成本变化:假设日固定管理成本增加20%; 预算调整:总建设预算调整为140万元。
  4.2 比较前后方案的变化,包括:站点数量与位置、服务定价、政府补贴总额、覆盖率、满意度等。分析模型对这些参数的敏感性,并评价模型的鲁棒性。
  4.3 指出模型在实际推广中可能面临的至少3个其他不确定因素,并给出应对策略建议。

整体求解过程概述(摘要)

  针对问题一,为了预测未来五年老人数量与服务需求,首先对人口结构、状态转移概率、服务频次、收入与消费上限进行数据一致性检验和术语归一化,将附件中的"半自理"统一为题面所称"半失能"。鉴于自理、半失能、失能具有单向转移与死亡流出特征,引入离散时间多状态人口递推模型,将年均7%的新增老人作为自理状态流入,并对三类老人统一施加5%的自然死亡率。模型得到第5年末老人总量约7578人,其中自理、半失能、失能分别约4982、1471、1126人。进一步构建服务需求张量与消费预算等比例削减模型,得到理论月需求262610次,消费约束后月需求247100次,需求压缩约5.91%。
  针对问题二,在问题一预测结果基础上,不再重复清洗同一数据,而是提取第5年末小区老人规模、可支付服务需求、距离矩阵和满意度分段规则作为特征。考虑站点位置、规模、容量、1000米服务半径和120万元建设预算的耦合关系,构建容量约束多目标最大覆盖模型,并采用"全方案编码枚举---预算剪枝---后悔值优先分配---响应满意度自洽校准"的求解流程。推荐在C小区建设中型站、I小区建设大型站、J小区建设中型站,建设成本109万元,实现100%覆盖,老人加权满意度约0.7273;三个站点利用率分别约90.40%、83.43%、84.09%。
  针对问题三,鉴于仅以满意度为目标会产生低价亏损的退化解,模型同时引入"保本微利"约束、政府按有效人次补贴及单站补贴上限。固定问题二的站点和服务分区,针对五项收费服务枚举价格满意度档位,并在每一档位内反求恰好保本的最低价格;为避免单一统一加价对全部服务造成不必要的满意度损失,进一步采用最小最大加价系数的公平分摊规则。优化后整体满意度提高到0.8222,价格满意度为0.9231,年度补贴总额226.30万元,各站利润率处于0---8%的允许区间。
  针对问题四,分别将新增老人率及状态转移概率调整、日固定管理成本提高20%、建设预算提高到140万元,并重新求解问题二和问题三。人口转移变化情景下推荐B、C、F、J四站方案,问题三满意度降至0.7960;管理成本增加不改变选址,但需要调整价格结构以维持保本;预算提高后推荐A、C、H、I四站方案,问题二满意度升至0.7709,问题三满意度升至0.9188。由站点集合Jaccard稳定度、满意度偏移和补贴变化可知,模型对运营成本具有结构稳定性,对人口需求和建设预算更敏感。
  综合而言,本文形成了"数据理解与探索---数据预处理---特征工程---人口与需求预测---选址规模优化---定价补贴优化---灵敏度与鲁棒性评价"的递进式模型体系。模型兼顾地理可达性、服务能力、价格负担、机构可持续运营与政府财政约束,并通过总量守恒、消费上限、容量利用率、满意度分段和利润率等多重条件进行交叉验证,可为成熟街道嵌入式养老服务网络的规划与动态调整提供量化依据。

模型假设:

  假设1 新增60岁老人均先进入自理状态;若现实中存在刚进入老年即半失能或失能者,可在推广模型中增加流入分配向量。
  假设2 自然死亡率对自理、半失能、失能三类老人相同,且死亡发生在年度状态转移后的同一统计周期内。
  假设3 五年内各小区人口结构、收入水平、服务偏好、工资物价和补贴政策除题设敏感性参数外保持稳定。
  假设4 同一小区老人面对同一站点时采用相同距离满意度;需求可按小区整体进行分区。
  假设5 老人优先选择满意度最高且仍具有接单能力的服务站;若首选站达到容量上限,则其即时响应能力视为不可用,转向次高满意度站。
  假设6 站点容量按照实际有效服务人次核算,月需求按30天折算为日均需求。
  假设7 问题二采用附件现行服务营收作为老人支付价格,附件中的直接支出列作为价格满意度基准价与成本基准。
  假设8 问题三要求机构不亏损且利润率不超过8%;在满意度相同的方案中优先选择老人支付总额最低的保本价格。
  假设9 一次性建设成本按20年等额折旧、无残值,并计入年度经济核算。

问题分析:

  问题一分析
  鉴于三类老人之间的转移具有明确方向,且题目给出的是年度转移概率,适合使用离散时间Markov型多状态递推。新增老人刚满60岁,通常首先进入自理状态,因此作为自理状态外生流入;自然死亡对三类状态均产生共同流出。服务需求预测则是"人数×人均频次"的张量乘积问题,而消费约束要求在理论费用超限时对各服务频次等比例削减,属于预算比例投影。
  问题二分析
  问题二同时包含离散站点位置、离散规模、服务半径、容量和多目标,属于容量约束最大覆盖选址问题的扩展。满意度中的距离项由空间位置决定,响应项由站点利用率分段决定,价格项在问题二中由现行价格确定。由于响应满意度又影响有效服务人次,从而反过来影响利用率,模型存在分段非线性自洽关系。考虑到仅有10个候选小区,每个位置有4种状态,可对4¹⁰种编码完整枚举,并在每个编码内部用容量可行分配与响应档位校准求解。
  问题三分析
  价格满意度为分段常数,而机构收入随价格连续变化,故可以采用"档位枚举+连续反求"的分层优化。先枚举五项收费服务所处的价格满意度档位,档位固定后有效服务人次和补贴可以计算;再在档位允许的价格区间内求使机构刚好保本的最低价格。该处理将复杂的分段非线性定价问题转化为有限组合搜索与一维水位分配,既可解释又便于验证。
  问题四分析
  灵敏度分析不能只在原解上代入新参数,因为人口变化和预算变化可能改变最优站点集合。因此本文对每一情景重新执行人口预测、需求生成、选址与定价求解。评价指标包括站点集合Jaccard相似度、覆盖率、满意度、补贴和价格成本倍数,并通过结构稳定性与输出偏移共同刻画鲁棒性。

模型的建立与求解整体论文缩略图

全部论文请见下方" 只会建模 QQ名片" 点击QQ名片即可

程序代码:

部分程序如下:
python 复制代码
from __future__ import annotations

import argparse
import csv
import json
import math
import os
import re
import sys
import zipfile
from dataclasses import dataclass
from pathlib import Path
from typing import Dict, List, Sequence, Tuple
from xml.etree import ElementTree as ET

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import font_manager

try:
    from numba import njit
except Exception:
    def njit(*args, **kwargs):
        def deco(func):
            return func
        return deco

COMMUNITIES = list("ABCDEFGHIJ")
SERVICES = ["助餐", "日间照料", "上门护理", "康复理疗", "助浴", "紧急救助"]
TYPES = ["自理", "半失能", "失能"]
SIZE_NAMES = ["不建设", "小型", "中型", "大型"]


def setup_chinese_font() -> None:
    for font_path in [
        "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc",
        "/usr/share/fonts/opentype/noto/NotoSansCJK-Bold.ttc",
    ]:
        if os.path.exists(font_path):
            try:
                font_manager.fontManager.addfont(font_path)
            except Exception:
                pass
    candidates = [
        "Noto Sans CJK SC", "Noto Sans CJK JP", "Source Han Sans SC",
        "Microsoft YaHei", "SimHei", "WenQuanYi Zen Hei", "Arial Unicode MS"
    ]
    available = {f.name for f in font_manager.fontManager.ttflist}
    for name in candidates:
        if name in available:
            plt.rcParams["font.sans-serif"] = [name]
            break
    plt.rcParams["axes.unicode_minus"] = False
    plt.rcParams["figure.dpi"] = 150
    plt.rcParams["savefig.dpi"] = 220


def _col_to_index(ref: str) -> int:
    letters = re.match(r"([A-Z]+)", ref).group(1)
    idx = 0
    for ch in letters:
        idx = idx * 26 + (ord(ch) - 64)
    return idx - 1


def read_xlsx(path: Path) -> Dict[str, List[List[object]]]:
    """读取 xlsx 中所有工作表,返回 {sheet_name: 2D values}。"""
    ns = {"m": "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
          "r": "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
          "p": "http://schemas.openxmlformats.org/package/2006/relationships"}
    with zipfile.ZipFile(path) as zf:
        shared: List[str] = []
        if "xl/sharedStrings.xml" in zf.namelist():
            root = ET.fromstring(zf.read("xl/sharedStrings.xml"))
            for si in root.findall("m:si", ns):
                shared.append("".join(t.text or "" for t in si.iterfind(".//m:t", ns)))
        wb = ET.fromstring(zf.read("xl/workbook.xml"))
        rels = ET.fromstring(zf.read("xl/_rels/workbook.xml.rels"))
        rel_map = {rel.attrib["Id"]: rel.attrib["Target"] for rel in rels.findall("p:Relationship", ns)}
        out: Dict[str, List[List[object]]] = {}
        for sh in wb.findall("m:sheets/m:sheet", ns):
            name = sh.attrib["name"]
            target = rel_map[sh.attrib[f"{{{ns['r']}}}id"]]
            target = target.lstrip("/")
            if not target.startswith("xl/"):
                target = "xl/" + target
            root = ET.fromstring(zf.read(target))
            cells: Dict[Tuple[int, int], object] = {}
            max_r = max_c = -1
            for c in root.findall(".//m:sheetData/m:row/m:c", ns):
                ref = c.attrib["r"]
                row = int(re.search(r"(\d+)$", ref).group(1)) - 1
                col = _col_to_index(ref)
                typ = c.attrib.get("t")
                v = c.find("m:v", ns)
                inline = c.find("m:is", ns)
                if typ == "s" and v is not None:
                    value: object = shared[int(v.text)]
                elif typ == "inlineStr" and inline is not None:
                    value = "".join(t.text or "" for t in inline.iterfind(".//m:t", ns))
                elif v is None:
                    value = None
                else:
                    raw = v.text or ""
                    if typ == "str":
                        value = raw
                    else:
                        try:
                            num = float(raw)
                            value = int(num) if num.is_integer() else num
                        except ValueError:
                            value = raw
                cells[(row, col)] = value
                max_r, max_c = max(max_r, row), max(max_c, col)
            values = [[None] * (max_c + 1) for _ in range(max_r + 1)]
            for (r, c), value in cells.items():
                values[r][c] = value
            out[name] = values
        return out


def numeric_matrix(rows: Sequence[Sequence[object]], row_start: int, row_end: int,
                   col_start: int, col_end: int) -> np.ndarray:
    return np.array([[float(rows[r][c]) for c in range(col_start, col_end)]
                     for r in range(row_start, row_end)], dtype=float)


@dataclass
class InputData:
    total_population: np.ndarray
    elderly: np.ndarray
    initial_by_type: np.ndarray
    income: np.ndarray
    transition: np.ndarray
    demand_per_elder: np.ndarray
    current_price: np.ndarray
    direct_cost: np.ndarray
    consumption_ratio: np.ndarray
    build_cost_10k: np.ndarray
    fixed_daily: np.ndarray
    capacity_daily: np.ndarray
    distances: np.ndarray
    subsidy_daily_cap: np.ndarray


def load_input(data_dir: Path) -> InputData:
    f1 = read_xlsx(data_dir / "附件1:小区基础数据.xlsx")
    f2 = read_xlsx(data_dir / "附件2:服务需求数据.xlsx")
    f3 = read_xlsx(data_dir / "附件3:服务站建设与运营成本.xlsx")
    f4 = read_xlsx(data_dir / "附件4:小区间距离矩阵.xlsx")

    pop = f1["人口与老人结构"]
    trans = f1["转移概率"]
    total_population = np.array([float(pop[r][1]) for r in range(2, 12)])
    elderly = np.array([float(pop[r][2]) for r in range(2, 12)])
    initial_by_type = np.array([[float(pop[r][3]), float(pop[r][4]), float(pop[r][5])]
                                for r in range(2, 12)])
    income = np.array([float(pop[r][6]) for r in range(2, 12)])
    transition = np.array([float(trans[2][1]), float(trans[3][1])])

    demand_rows = f2["每位老人月均服务需求次数"]
    # 附件中的"半自理"与题面"半失能"视为同一类别,统一为"半失能"
    demand_per_elder = np.array([[float(demand_rows[r][c]) for r in range(2, 8)]
                                 for c in range(1, 4)])
    rev_rows = f2["服务营收及支出"]
    current_price = np.array([float(re.findall(r"[-+]?\d*\.?\d+", str(rev_rows[r][1]))[0])
                              for r in range(2, 8)])
    direct_cost = np.array([float(re.findall(r"[-+]?\d*\.?\d+", str(rev_rows[r][2]))[0])
                            for r in range(2, 8)])
    consumption_ratio = np.array([0.20, 0.25, 0.30])

    cost_rows = f3["服务站建设与运营成本"]
    build_cost_10k = np.array([0.0] + [float(cost_rows[r][1]) for r in range(2, 5)])
    fixed_daily = np.array([0.0] + [float(cost_rows[r][2]) for r in range(2, 5)])
    capacity_daily = np.array([0.0] + [float(cost_rows[r][3]) for r in range(2, 5)])

    dist_rows = f4["小区间距离矩阵"]
    distances = numeric_matrix(dist_rows, 2, 12, 1, 11)
    subsidy_daily_cap = np.array([0.0, 1000.0, 1800.0, 2600.0])
    return InputData(total_population, elderly, initial_by_type, income, transition,
                     demand_per_elder, current_price, direct_cost, consumption_ratio,
                     build_cost_10k, fixed_daily, capacity_daily, distances,
                     subsidy_daily_cap)


def validate_data(data: InputData) -> Dict[str, float]:
    residual = np.abs(data.initial_by_type.sum(axis=1) - data.elderly)
    symmetry = np.abs(data.distances - data.distances.T)
    return {
        "population_structure_max_residual": float(residual.max()),
        "distance_symmetry_max_residual": float(symmetry.max()),
        "distance_diagonal_max": float(np.abs(np.diag(data.distances)).max()),
        "missing_count": 0.0,
    }


def project_population(data: InputData, years: int = 5, entrant_rate: float = 0.07,
                       death_rate: float = 0.05, p_self_half: float | None = None,
                       p_half_disabled: float | None = None) -> np.ndarray:
    p = data.transition[0] if p_self_half is None else p_self_half
    q = data.transition[1] if p_half_disabled is None else p_half_disabled
    hist = np.zeros((years + 1, 10, 3), dtype=float)
    hist[0] = data.initial_by_type
    for t in range(years):
        s, h, d = hist[t].T
        total = s + h + d
        hist[t + 1, :, 0] = (1 - death_rate) * (1 - p) * s + entrant_rate * total
        hist[t + 1, :, 1] = (1 - death_rate) * (p * s + (1 - q) * h)
        hist[t + 1, :, 2] = (1 - death_rate) * (q * h + d)
    return hist


def demand_forecast(data: InputData, population_year5: np.ndarray) -> Dict[str, np.ndarray]:
    theoretical = population_year5[:, :, None] * data.demand_per_elder[None, :, :]
    per_elder_cost = data.demand_per_elder @ data.current_price
    cap = data.income[:, None] * data.consumption_ratio[None, :]
    scale = np.minimum(1.0, cap / per_elder_cost[None, :])
    constrained = theoretical * scale[:, :, None]
    return {
        "theoretical": theoretical,
        "constrained": constrained,
        "scale": scale,
        "per_elder_cost": per_elder_cost,
        "cap": cap,
        "community_service": constrained.sum(axis=1),
    }


def distance_score(d: float) -> float:
    if d <= 300: return 1.00
    if d <= 500: return 0.90
    if d <= 650: return 0.75
    if d <= 1000: return 0.60
    return 0.0


@njit(cache=True)
def _search_configs_numba(elder: np.ndarray, demand_total: np.ndarray, price_score_comm: np.ndarray,
                          distances: np.ndarray, build_cost: np.ndarray, capacities: np.ndarray,
                          budget: float):
    n = 10
    s2_levels = np.array([1.0, 0.93, 0.85, 0.72, 0.60])
    low = np.array([0.0, 0.60, 0.75, 0.85, 0.95])
    high = np.array([0.60, 0.75, 0.85, 0.95, 1.00])
    total_elder = elder.sum()
    best_cov, best_sat, best_cost = -1.0, -1.0, 1e30
    best_cfg = np.zeros(n, np.int64)
    best_ass = np.full(n, -1, np.int64)
    best_sati = np.zeros(n)
    best_util = np.zeros(n)
    best_s2 = np.zeros(n)
    best_m = 0
    # 用于画可行方案散点,最大可行数小于 20000
    metr_cost = np.zeros(20000)
    metr_cov = np.zeros(20000)
    metr_sat = np.zeros(20000)
    metr_count = np.zeros(20000)
    mc = 0
    total_codes = 1
    for _ in range(n): total_codes *= 4
    for code in range(1, total_codes):
        tmp = code
        cfg = np.zeros(n, np.int64)
        sites = np.zeros(n, np.int64)
        m, cost = 0, 0.0
        for j in range(n):
            cfg[j] = tmp & 3
            tmp >>= 2
            cost += build_cost[cfg[j]]
            if cfg[j] > 0:
                sites[m] = j; m += 1
        if cost > budget: continue
        geometric = True
        for i in range(n):
            ok = False
            for q in range(m):
                if distances[i, sites[q]] <= 1000:
                    ok = True; break
            if not ok:
                geometric = False; break
        if not geometric: continue
        s2 = np.ones(m)
        local_cov, local_sat = -1.0, -1.0
        local_ass = np.full(n, -1, np.int64)
        local_sati = np.zeros(n)
        local_util = np.zeros(m)
        local_s2 = np.zeros(m)
        for _it in range(30):
            score = np.full((n, m), -99.0)
            regret = np.zeros(n)
            for i in range(n):
                first, second = -99.0, -99.0
                for q in range(m):
                    j = sites[q]
                    if distances[i, j] <= 1000:
                        d = distances[i, j]
                        s1 = 1.0 if d <= 300 else (0.9 if d <= 500 else (0.75 if d <= 650 else 0.6))
                        sc = 0.2*s1 + 0.3*s2[q] + 0.5*price_score_comm[i]
                        score[i, q] = sc
                        if sc > first:
                            second, first = first, sc
                        elif sc > second:
                            second = sc
                regret[i] = first - second if m > 1 else first + 99.0
            order = np.arange(n)
            # 选择排序,按后悔值降序
            for a in range(n-1):
                pos = a
                for b in range(a+1, n):
                    if regret[order[b]] > regret[order[pos]]:
                        pos = b
                v = order[a]; order[a] = order[pos]; order[pos] = v
            rem = np.zeros(m)
            for q in range(m): rem[q] = 30.0*capacities[cfg[sites[q]]]
            ass = np.full(n, -1, np.int64)
            for oo in range(n):
                i = order[oo]
                chosen = np.zeros(m, np.bool_)
                for _k in range(m):
                    bestq, bestscore = -1, -100.0
                    for q in range(m):
                        if not chosen[q] and score[i, q] > bestscore:
                            bestq, bestscore = q, score[i, q]
                    if bestq < 0 or bestscore < 0: break
                    chosen[bestq] = True
                    load = demand_total[i] * bestscore
                    if rem[bestq] + 1e-9 >= load:
                        ass[i] = bestq
                        rem[bestq] -= load
                        break
            # 根据当前分区直接寻找自洽响应等级
            ns2 = np.zeros(m); util = np.zeros(m)
            feasible = True
            for q in range(m):
                j = sites[q]
                found = False
                for r in range(5):
                    load = 0.0
                    for i in range(n):
                        if ass[i] == q:
                            d = distances[i, j]
                            s1 = 1.0 if d <= 300 else (0.9 if d <= 500 else (0.75 if d <= 650 else 0.6))
                            sc = 0.2*s1 + 0.3*s2_levels[r] + 0.5*price_score_comm[i]
                            load += demand_total[i]*sc
                    u = load/(30.0*capacities[cfg[j]])
                    if u >= low[r]-1e-9 and u <= high[r]+1e-9:
                        ns2[q], util[q], found = s2_levels[r], u, True
                        break
                if not found:
                    feasible = False; break
            if not feasible: break
            cov_sum, sat_sum = 0.0, 0.0
            sati = np.zeros(n)
            for i in range(n):
                if ass[i] >= 0:
                    q = ass[i]; j = sites[q]; d = distances[i, j]
                    s1 = 1.0 if d <= 300 else (0.9 if d <= 500 else (0.75 if d <= 650 else 0.6))
                    sati[i] = 0.2*s1 + 0.3*ns2[q] + 0.5*price_score_comm[i]
                    cov_sum += elder[i]
                    sat_sum += elder[i]*sati[i]
            cov, sat = cov_sum/total_elder, sat_sum/total_elder
            if cov > local_cov+1e-12 or (abs(cov-local_cov) <= 1e-12 and sat > local_sat+1e-12):
                local_cov, local_sat = cov, sat
                local_ass[:] = ass; local_sati[:] = sati
                local_util[:] = util; local_s2[:] = ns2
            same = True
            for q in range(m):
                if abs(ns2[q]-s2[q]) > 1e-12: same = False
                s2[q] = ns2[q]
            if same: break
        if local_cov < 0: continue
        if mc < 20000:
            metr_cost[mc], metr_cov[mc], metr_sat[mc], metr_count[mc] = cost, local_cov, local_sat, m
            mc += 1
        if (local_cov > best_cov+1e-12 or
            (abs(local_cov-best_cov) <= 1e-12 and
             (local_sat > best_sat+1e-12 or
              (abs(local_sat-best_sat) <= 1e-12 and cost < best_cost-1e-12)))):
            best_cov, best_sat, best_cost = local_cov, local_sat, cost
            best_cfg[:] = cfg; best_ass[:] = local_ass; best_sati[:] = local_sati
            best_m = m
            for q in range(m): best_util[q], best_s2[q] = local_util[q], local_s2[q]
    return (best_cfg, best_ass, best_sati, best_util, best_s2, best_m,
            best_cov, best_sat, best_cost,
            metr_cost[:mc], metr_cov[:mc], metr_sat[:mc], metr_count[:mc])
全部论文请见下方" 只会建模 QQ名片" 点击QQ名片即可
相关推荐
databook2 小时前
如何对稀疏数据的场景进行分析
python·数据挖掘·数据分析
wang_yb3 小时前
如何对稀疏数据的场景进行分析
数据分析·databook
科技每日热闻10 小时前
AI 赋能财务资金管理、风险预警、经营数据分析,合适的云上财务智能 Agent 有哪些?—— 优先采用 Amazon Quick 四链路解决方案
人工智能·ai·数据挖掘·数据分析
观远数据1 天前
AI+BI时代的数据合规三重门:传输、存储、消费如何一体化管控
大数据·数据分析
@insist1231 天前
系统集成项目管理工程师-数据分析应用与数据安全
数据分析·软考·系统集成项目管理工程师·软考中项·软件水平考试
2601_953988071 天前
Ricon组态系统vs传统组态软件:为什么选择新一代Web组态平台
前端·后端·物联网·tcp/ip·数学建模·前端框架
不剪发的Tony老师2 天前
Dash:一款免费开源、本地优先的数据探索与可视化工具
数据分析·数据可视化·dash
davawang2 天前
数据虚拟化技术解析:从概念到实践
数据分析·数据平台·管理工具
数模竞赛Paid answer2 天前
2026年华东杯数学建模C题收益率预测问题解题全过程文档及程序
算法·数学建模·数据分析·华东杯