爆款云主机2核4G限时秒杀,88元/年起!
查看详情

活动

天翼云最新优惠活动,涵盖免费试用,产品折扣等,助您降本增效!
热门活动
  • 618智算钜惠季 爆款云主机2核4G限时秒杀,88元/年起!
  • 免费体验DeepSeek,上天翼云息壤 NEW 新老用户均可免费体验2500万Tokens,限时两周
  • 云上钜惠 HOT 爆款云主机全场特惠,更有万元锦鲤券等你来领!
  • 算力套餐 HOT 让算力触手可及
  • 天翼云脑AOne NEW 连接、保护、办公,All-in-One!
  • 中小企业应用上云专场 产品组合下单即享折上9折起,助力企业快速上云
  • 息壤高校钜惠活动 NEW 天翼云息壤杯高校AI大赛,数款产品享受线上订购超值特惠
  • 天翼云电脑专场 HOT 移动办公新选择,爆款4核8G畅享1年3.5折起,快来抢购!
  • 天翼云奖励推广计划 加入成为云推官,推荐新用户注册下单得现金奖励
免费活动
  • 免费试用中心 HOT 多款云产品免费试用,快来开启云上之旅
  • 天翼云用户体验官 NEW 您的洞察,重塑科技边界

智算服务

打造统一的产品能力,实现算网调度、训练推理、技术架构、资源管理一体化智算服务
智算云(DeepSeek专区)
科研助手
  • 算力商城
  • 应用商城
  • 开发机
  • 并行计算
算力互联调度平台
  • 应用市场
  • 算力市场
  • 算力调度推荐
一站式智算服务平台
  • 模型广场
  • 体验中心
  • 服务接入
智算一体机
  • 智算一体机
大模型
  • DeepSeek-R1-昇腾版(671B)
  • DeepSeek-R1-英伟达版(671B)
  • DeepSeek-V3-昇腾版(671B)
  • DeepSeek-R1-Distill-Llama-70B
  • DeepSeek-R1-Distill-Qwen-32B
  • Qwen2-72B-Instruct
  • StableDiffusion-V2.1
  • TeleChat-12B

应用商城

天翼云精选行业优秀合作伙伴及千余款商品,提供一站式云上应用服务
进入甄选商城进入云市场创新解决方案
办公协同
  • WPS云文档
  • 安全邮箱
  • EMM手机管家
  • 智能商业平台
财务管理
  • 工资条
  • 税务风控云
企业应用
  • 翼信息化运维服务
  • 翼视频云归档解决方案
工业能源
  • 智慧工厂_生产流程管理解决方案
  • 智慧工地
建站工具
  • SSL证书
  • 新域名服务
网络工具
  • 翼云加速
灾备迁移
  • 云管家2.0
  • 翼备份
资源管理
  • 全栈混合云敏捷版(软件)
  • 全栈混合云敏捷版(一体机)
行业应用
  • 翼电子教室
  • 翼智慧显示一体化解决方案

合作伙伴

天翼云携手合作伙伴,共创云上生态,合作共赢
天翼云生态合作中心
  • 天翼云生态合作中心
天翼云渠道合作伙伴
  • 天翼云代理渠道合作伙伴
天翼云服务合作伙伴
  • 天翼云集成商交付能力认证
天翼云应用合作伙伴
  • 天翼云云市场合作伙伴
  • 天翼云甄选商城合作伙伴
天翼云技术合作伙伴
  • 天翼云OpenAPI中心
  • 天翼云EasyCoding平台
天翼云培训认证
  • 天翼云学堂
  • 天翼云市场商学院
天翼云合作计划
  • 云汇计划
天翼云东升计划
  • 适配中心
  • 东升计划
  • 适配互认证

开发者

开发者相关功能入口汇聚
技术社区
  • 专栏文章
  • 互动问答
  • 技术视频
资源与工具
  • OpenAPI中心
开放能力
  • EasyCoding敏捷开发平台
培训与认证
  • 天翼云学堂
  • 天翼云认证
魔乐社区
  • 魔乐社区

支持与服务

为您提供全方位支持与服务,全流程技术保障,助您轻松上云,安全无忧
文档与工具
  • 文档中心
  • 新手上云
  • 自助服务
  • OpenAPI中心
定价
  • 价格计算器
  • 定价策略
基础服务
  • 售前咨询
  • 在线支持
  • 在线支持
  • 工单服务
  • 建议与反馈
  • 用户体验官
  • 服务保障
  • 客户公告
  • 会员中心
增值服务
  • 红心服务
  • 首保服务
  • 客户支持计划
  • 专家技术服务
  • 备案管家

了解天翼云

天翼云秉承央企使命,致力于成为数字经济主力军,投身科技强国伟大事业,为用户提供安全、普惠云服务
品牌介绍
  • 关于天翼云
  • 智算云
  • 天翼云4.0
  • 新闻资讯
  • 天翼云APP
基础设施
  • 全球基础设施
  • 信任中心
最佳实践
  • 精选案例
  • 超级探访
  • 云杂志
  • 分析师和白皮书
  • 天翼云·创新直播间
市场活动
  • 2025智能云生态大会
  • 2024智算云生态大会
  • 2023云生态大会
  • 2022云生态大会
  • 天翼云中国行
天翼云
  • 活动
  • 智算服务
  • 产品
  • 解决方案
  • 应用商城
  • 合作伙伴
  • 开发者
  • 支持与服务
  • 了解天翼云
      • 文档
      • 控制中心
      • 备案
      • 管理中心

      探索经典算法:贪心、分治、动态规划等

      首页 知识中心 大数据 文章详情页

      探索经典算法:贪心、分治、动态规划等

      2024-10-29 09:40:28 阅读次数:30

      dp,数组

      1.贪心算法

      贪心算法是一种常见的算法范式,通常在解决最优化问题中使用。
      贪心算法是一种在每一步选择中都采取当前状态下最优决策的算法范式。其核心思想是选择每一步的最佳解决方案,以期望达到最终的全局最优解。这种算法特点在于只考虑局部最优解,而不会回溯或重新考虑已经做出的决策,也不保证能够解决所有问题。尽管贪心算法并非适用于所有问题,但对于某些特定类型的问题,贪心算法的思路简单、高效。

      1.区间调度

      题目描述:

      作业j从sj开始,在fj结束

      如果两个作业不重叠,则它们是兼容的。

      目标:找到相互兼容作业的最大子集。

      探索经典算法:贪心、分治、动态规划等

      解题思路分析:

      要使用贪心算法解决这个问题,我们可以按照以下步骤进行:

      1. 按照作业的结束时间对作业列表进行排序,确保作业按照结束时间的升序排列。
      2. 初始化一个空的最大互相兼容作业子集max_jobs_subset。
      3. 从排序后的作业列表中选择第一个作业,并将其添加到max_jobs_subset中。
      4. 遍历剩余的作业,对于每个作业:
        • 检查该作业的起始时间是否晚于max_jobs_subset中最后一个作业的结束时间。
        • 如果是,则将该作业添加到max_jobs_subset中。
      5. 返回max_jobs_subset作为最大互相兼容作业子集。

      python代码:

      # 定义一个job类
      class Job:
          def __init__(self, start_time, finsh_time):
              self.start_time = start_time
              self.finsh_time = finsh_time
      
      def find_max_compatible_jobs(jobs):
          # 使用sort函数对jobs列表进行排序 这里按照结束时间升序排列
          jobs.sort(key=lambda x: x.finsh_time)
          max_jobs_subset = []
          last_time = float('-inf')
          for job in jobs:
              if job.start_time >=last_time:
                  max_jobs_subset.append(job)
                  last_time = job.finsh_time
          # 这里直接返回最大公共子集
          return max_jobs_subset
      # 编写测试函数
      # 用户首先输入作业的数量
      while True:
          try:
              job_count = int(input('请输入作业总数:'))
              if job_count < 1:
                  raise ValueError
              break
          except ValueError:
              print('作业总数必须是一个正整数')
      #  定义工作列表存储用户输入的工作
      jobs = []
      # 依次输入每个作业的起始时间和结束时间
      for i in range(job_count):
          while True:
              try:
                  start_time = int(input('请输入第{}个作业的起始时间:'.format(i + 1)))
                  finsh_time = int(input('请输入第{}个作业的结束时间:'.format(i + 1)))
                  if finsh_time < start_time:
                      raise ValueError
                  break
              except ValueError:
                  print('结束时间必须晚于开始时间')
          job = Job(start_time,finsh_time)
          jobs.append(job)
      # 调用函数找到最大互相兼容作业子集
      max_compatible_jobs = find_max_compatible_jobs(jobs)
      print('相互兼容的最大工作子集:')
      for job in max_compatible_jobs:
          print('作业开始时间:{},作业结束时间:{}'.format(job.start_time,job.finsh_time))
      

      2.区间划分

      题目描述:

      讲座j 从sj开始,到fj结束;
      目标:找到安排所有讲座的最少教室数量
      这样就不会在同一个房间里同时发生两次讲座。

      解题思路分析:

      具体的求解过程如下:

      1. 将所有的讲座按照结束时间进行排序,可以使用 sorted 函数,并将 key 参数设置为讲座的结束时间。这样可以保证在贪心算法中,我们首先处理最早结束的讲座。
      2. 创建一个空的教室列表,用于存储已经安排的讲座。
      3. 遍历排序后的讲座列表。对于每一个讲座,我们需要检查是否存在一个教室可以容纳它。
      4. 对于每个讲座,我们遍历已经安排的教室,并检查当前讲座是否可以安排在某个教室中。我们可以通过比较当前讲座的开始时间和已安排讲座的结束时间来判断是否可以安排在同一个教室中。
      5. 如果存在一个教室可以容纳当前讲座,则将该讲座添加到教室的列表中。
      6. 如果不存在可以容纳当前讲座的教室,则创建一个新的教室,并将当前讲座添加到新的教室中。
      7. 遍历完所有的讲座后,返回教室列表的长度,即为需要的最小教室数量。

      python代码:

      class Lecture:
          def __init__(self, start_time, end_time):
              self.start_time = start_time
              self.end_time = end_time
      def get_valid_lectures():
          lectures = []
          while True:
              try:
                  num_lectures = int(input("请输入讲座数量: "))
                  if num_lectures <= 0:
                      raise ValueError("讲座数量必须大于0")
                  for i in range(num_lectures):
                      start_time = int(input(f"请输入讲座{i + 1}的开始时间: "))
                      end_time = int(input(f"请输入讲座{i + 1}的结束时间: "))
                      if start_time >= end_time:
                          raise ValueError(f"讲座{i + 1}的开始时间必须早于结束时间")
                      if start_time < 0:
                          raise ValueError(f'讲座{i+1}的开始时间必须是正数')
                      if end_time < 0:
                          raise ValueError(f'讲座{i+1}的结束时间必须是正数')
                      lecture = Lecture(start_time, end_time)
                      lectures.append(lecture)
                  break
              except ValueError as e:
                  print("输入错误:", e)
          return lectures
      
      
      def minimum_classrooms(lectures):
          sorted_lectures = sorted(lectures, key=lambda x: x.end_time)
          classrooms = []
          for lecture in sorted_lectures:
              found_classroom = False
              for classroom in classrooms:
                  if lecture.start_time >= classroom[-1].end_time:
                      classroom.append(lecture)
                      found_classroom = True
                      break
      
              if not found_classroom:
                  classrooms.append([lecture])
      
          return len(classrooms)
      
      # 获取有效的讲座数据
      valid_lectures = get_valid_lectures()
      # 调用函数获取最小教室数量
      min_classrooms = minimum_classrooms(valid_lectures)
      print("需要的最小教室数量:", min_classrooms)
      

      3.最小延迟时间

      题目描述:

      ・单个资源一次处理一个作业。

      ・作业j需要tj个处理时间单位,并且在时间dj到期

      ・如果j在时间sj开始,它在时间fj=sj+tj结束

      ・潜伏时间:ℓj=最大{0,fj–dj}。

      ・目标:安排所有作业以最大限度地减少最大延迟L=maxjℓj

      解题思路分析:

      1. 首先,将所有的任务按照截止时间 dj 进行排序,以确保优先处理截止时间最早的任务。
      2. 创建一个空闲时间变量 current_time,并初始化为 0。
      3. 对每个任务进行迭代,按照排序后的顺序:
        • 计算当前任务的完成时间 fj = current_time + tj,其中 tj 是当前任务的处理时间。
        • 计算当前任务的延迟时间 ℓj = max(0, fj - dj)。
        • 更新最大延迟 L,如果当前任务的延迟时间 ℓj 大于 L,则将 L 更新为 ℓj。
        • 更新当前时间 current_time,将其设置为当前任务的完成时间 fj。
      4. 返回最大延迟 L。

      Python代码:

      class Job:
          def __init__(self, processing_time, deadline):
              self.processing_time = processing_time
              self.deadline = deadline
      
      def minimum_lateness(jobs):
          jobs.sort(key=lambda x: x.deadline)  # 按照截止时间排序
          L = 0  # 最大延迟
          current_time = 0  # 当前时间
          for job in jobs:
              # 验证处理时间和截止时间的格式和数值
              if not isinstance(job.processing_time, int) or job.processing_time <= 0:
                  raise ValueError("Processing time should be a positive integer.")
              if not isinstance(job.deadline, int) or job.deadline <= 0:
                  raise ValueError("Deadline should be a positive integer.")
      
              # 计算完成时间和延迟时间
              finish_time = current_time + job.processing_time
              lateness = max(0, finish_time - job.deadline)
      
              # 更新最大延迟
              L = max(L, lateness)
      
              # 更新当前时间
              current_time = finish_time
      
          return L
      
      
      # 用户输入数据
      n = None
      while not isinstance(n, int) or n <= 0:
          try:
              n = int(input("Enter the number of jobs: "))
              if n <= 0:
                  print("Number of jobs should be a positive integer.")
          except ValueError:
              print("Invalid input. Number of jobs should be an integer.")
      
      jobs = []
      for i in range(n):
          print(f"Enter information for job {i+1}:")
          processing_time = None
          while not isinstance(processing_time, int) or processing_time <= 0:
              try:
                  processing_time = int(input("Enter the processing time: "))
                  if processing_time <= 0:
                      print("Processing time should be a positive integer.")
              except ValueError:
                  print("Invalid input. Processing time should be an integer.")
      
          deadline = None
          while not isinstance(deadline, int) or deadline <= 0:
              try:
                  deadline = int(input("Enter the deadline: "))
                  if deadline <= 0:
                      print("Deadline should be a positive integer.")
              except ValueError:
                  print("Invalid input. Deadline should be an integer.")
      
          job = Job(processing_time, deadline)
          jobs.append(job)
      
      try:
          max_lateness = minimum_lateness(jobs)
          print("The maximum lateness is:", max_lateness)
      except ValueError as e:
          print("Invalid input:", str(e))
      

      2.分治算法

      分治算法是一种重要的算法范式,它将一个大问题分解成几个小问题,分别解决这些小问题,然后将其合并以得到原始问题的解。其核心思想是递归地把问题分解成更小的子问题,并将这些子问题独立地解决。

      分治算法的设计思路通常分为三个步骤:

      1. 分解:将原问题分解为若干个子问题。
      2. 解决:递归地解决这些子问题。
      3. 合并:将子问题的解合并成原问题的解。

      分治算法常用于解决递归性质的问题,例如归并排序、快速排序、二叉树相关问题等。虽然它的效率通常较高,但并非适用于所有问题。

      1.最近配对问题

      题目描述:

      最近配对问题。给定平面上的n个点,找一对点,使得它们之间的欧几里得距离最小。

      解题思路分析:

      分治法是一种解决问题的方法,将问题划分为更小的子问题,然后将子问题的解合并起来得到原问题的解。下面是使用分治法解决最近配对问题的详细步骤:

      1. 将所有点按照 x 坐标进行排序。
      2. 将点集分为左右两部分,分别记为 P_left 和 P_right。
      3. 递归地在 P_left 和 P_right 中分别找到最近配对的距离,记为 d_left 和 d_right。
      4. 取 d_left 和 d_right 中的较小值,记为 d。
      5. 在左右两个点集中,找到横跨中间区域的点集 P_mid,其 x 坐标与中间点的 x 坐标的差值小于等于 d。
      6. 在 P_mid 中按照 y 坐标进行排序。
      7. 遍历 P_mid 中的每个点,对于每个点 p,只需计算与其后续的 7 个点的距离(因为在排序后的 P_mid 中,距离任意两点最大为 d)。
      8. 找到 P_mid 中距离最小的两个点的距离,记为 d_mid。
      9. 返回 d、d_left 和 d_right 中的最小值作为最终的最近配对距离。

      python代码:

      import math
      # 定义一个坐标类 包括x和y
      class Point:
          def __init__(self, x, y):
              self.x = x
              self.y = y
      # 求解两个点的欧几里得距离
      def distance(p1, p2):
          return math.sqrt((p1.x-p2.x)**2+(p1.y-p2.y)**2)
      # 使用分治法求解最近配对问题
      def closest_pair(points):
          n = len(points)
      #     这里如果n小于等于3 即直接使用暴力法计算
          if n <= 3:
              # 默认最小距离为最大值
              min_distance = float('inf')
              closest_points = None
              for i in range(n):
                  for j in range(i+1, n):
                      if distance(points[i], points[j]) < min_distance:
                          min_distance = distance(points[i], points[j])
                          closest_points = (points[i], points[j])
              #函数直接返回最短距离点对和最小距离
              return closest_points, min_distance
      #     如果点集个数大于3 则使用分治法求解
      #     首先对点集按照x升序排列
          points.sort(key=lambda p: p.x)
      #     然后将点集分为两部分
          mid = n // 2
          left_points = points[:mid]
          right_points = points[mid:]
      #     分别求解左 右区间的最小距离与最近点集
          closest_left, d_left = closest_pair(left_points)
          closest_right, d_right = closest_pair(right_points)
          if d_left < d_right:
              d = d_left
              closest_points = closest_left
          else:
              d = d_right
              closest_points = closest_right
          mid_x = (points[mid-1].x+points[mid].x)/2
          mid_points = [p for p in points if abs(p.x-mid_x) < d]
      #     然后把这些点按照y值排序
          mid_points.sort(key=lambda p: p.y)
          min_distance = d
          for i in range(len(mid_points)):
              for j in range(i+1, min(i+8, len(mid_points))):# 最多计算后序7个点的距离
                  if distance(points[i], points[j]) < d:
                      min_distance = distance(points[i], points[j])
                      closest_points = (points[i], points[j])
          return closest_points, min_distance
      # 获取用户输入的点坐标
      points = []
      while True:
          x_input = input("请输入点的 x 坐标(输入 'end' 结束输入): ")
          if x_input == 'end':
              break
          y_input = input("请输入点的 y 坐标(输入 'end' 结束输入): ")
          if y_input == 'end':
              break
          try:
              x = float(x_input)
              y = float(y_input)
              # 进行校验逻辑,例如对 x 和 y 坐标进行合法性检查、范围检查等,根据需求自行定义
              # 如果校验通过,则创建 Point 对象并添加到 points 列表中
              point = Point(x, y)
              points.append(point)
          except ValueError:
              print("输入的坐标不合法,请重新输入")
      
      # 调用 closest_pair() 函数获取最近配对的结果
      closest_points, min_distance = closest_pair(points)
      point1, point2 = closest_points
      
      # 输出最近配对的距离和坐标
      print("The closest pair distance is:", min_distance)
      print("The closest pair coordinates are:", (point1.x, point1.y), (point2.x, point2.y))
      

      2.第k小元素

      题目描述:

      给定一个完全有序的宇宙中的n个元素,找出第k个最小的元素。

      解题思路分析:

      1. 首先,我们需要选择一个合适的基准元素。可以使用各种方法选择基准元素,例如选择第一个元素、最后一个元素或随机选择一个元素。选择一个好的基准元素可以提高算法的效率。
      2. 将数组划分为两个子数组,一个包含小于等于基准元素的元素,另一个包含大于基准元素的元素。这可以通过遍历数组,并将小于等于基准元素的元素放在一个子数组中,大于基准元素的元素放在另一个子数组中来实现。这个过程通常被称为分区(partition)。
      3. 然后,我们需要确定基准元素在整个数组中的位置。这可以通过分区的过程中,记录基准元素的位置来实现。假设基准元素的位置是 pivot_index。
      4. 现在,我们可以根据 pivot_index 与 k 的关系来决定继续查找的部分:
        • 如果 pivot_index == k-1,说明基准元素正好是第 k 小的元素,返回它。
        • 如果 pivot_index > k-1,说明第 k 小的元素在基准元素的左边,我们可以递归地在左边的子数组中查找第 k 小的元素。
        • 如果 pivot_index < k-1,说明第 k 小的元素在基准元素的右边,我们可以递归地在右边的子数组中查找第 k-pivot_index-1 小的元素。
      5. 递归地应用上述步骤,直到找到第 k 小的元素。

      python代码实现:

      def choose_pivot(arr, low, high):
          mid = (low + high) // 2
          if arr[low] <= arr[mid] <= arr[high] or arr[high] <= arr[mid] <= arr[low]:
              return mid
          elif arr[mid] <= arr[low] <= arr[high] or arr[high] <= arr[low] <= arr[mid]:
              return low
          else:
              return high
      
      # 分区 分为小于基准元素和大于基准元素两个数组
      def partition(arr, low, high):
          # 通过三数取中找到基准元素
          pivot_index = choose_pivot(arr, low, high)
          pivot = arr[pivot_index]
          i = low - 1
          arr[pivot_index], arr[high] = arr[high], arr[pivot_index]
      
          for j in range(low, high):
              if arr[j] <= pivot:
                  i += 1
                  arr[i], arr[j] = arr[j], arr[i]
      
          arr[i+1], arr[high] = arr[high], arr[i+1]
          return i+1
      
      def kth_smallest(arr, low, high, k):
          if low == high:
              return arr[low]
          pivot_index = partition(arr, low, high)
          if pivot_index == k-1:
              return arr[pivot_index]
          elif pivot_index > k-1:
              return kth_smallest(arr, low, pivot_index-1, k)
          else:
              return kth_smallest(arr, pivot_index+1, high, k)
      
      # 用户输入数据
      arr_valid = False
      arr = []
      while not arr_valid:
          arr = input("请输入由空格分隔的整数数组:").split()
          if arr:
              try:
                  arr = [int(num) for num in arr]
                  arr_valid = True
              except ValueError:
                  print("输入无效,请重新输入整数数组。")
          else:
              print("输入数组不能为空。")
      
      # 校验数据有效性
      k_valid = False
      k = 0
      while not k_valid:
          k = input("请输入要查找的第几小的元素的值:")
          if k.isdigit():
              k = int(k)
              if 1 <= k <= len(arr):
                  k_valid = True
              else:
                  print("输入的值超出了数组范围,请重新输入。")
          else:
              print("输入无效,请重新输入一个整数。")
      
      kth_smallest_element = kth_smallest(arr, 0, len(arr)-1, k)
      print(f"The {k}th smallest element is: {kth_smallest_element}")
      

      3.医院医生算法

      题目描述:

      医院-医生算法是一种解决问题的方法,旨在以最佳方式将医生分配给医院。该算法确保每个医院都有足够数量的医生,并根据特定的标准将每个医生分配到合适的医院。

      解题思路分析:

      以下是使用稳定婚姻算法解决医院-医生分配问题的步骤:

      1. 初始化医生和医院的偏好列表,并将所有医生和医院都标记为未匹配状态。
      2. 对于每个医生,按照其对医院的偏好将医生依次提议给最喜欢的医院。每个医生只能向一个医院提议。
      3. 对于每个医院收到的提议,根据医院的偏好列表进行选择。如果医院尚未被匹配,将医生分配给该医院。如果医院已经有医生,比较当前医生和已匹配医生对医院的偏好,并选择更受欢迎的医生。
      4. 如果医生被匹配到医院,医生和医院都将标记为已匹配状态。
      5. 如果有医生被拒绝或医院已经达到容量上限,则该医生将继续向下一个偏好医院提议。
      6. 重复步骤2和步骤3,直到所有医生都被匹配到医院为止。
      7. 最终得到的医生-医院匹配结果即为最优的医院-医生分配方案。

      python代码:

      def stable_marriage(doctors, hospitals):
          doctor_preferences = {}
          hospital_preferences = {}
          doctor_matches = {}
          hospital_matches = {}
      
          # 初始化医生和医院的偏好列表
          for doctor in doctors:
              doctor_preferences[doctor] = doctors[doctor]
      
          for hospital in hospitals:
              hospital_preferences[hospital] = hospitals[hospital]
      
          # 将所有医生和医院都标记为未匹配状态
          for doctor in doctors:
              doctor_matches[doctor] = None
      
          for hospital in hospitals:
              hospital_matches[hospital] = None
      
          while None in doctor_matches.values():
              for doctor in doctors:
                  if doctor_matches[doctor] is None:
                      for hospital in doctor_preferences[doctor]:
                          if hospital_matches[hospital] is None:
                              doctor_matches[doctor] = hospital
                              hospital_matches[hospital] = doctor
                              break
                          else:
                              current_match = hospital_matches[hospital]
                              if hospital_preferences[hospital].index(doctor) < hospital_preferences[hospital].index(current_match):
                                  doctor_matches[doctor] = hospital
                                  doctor_matches[current_match] = None
                                  hospital_matches[hospital] = doctor
                                  break
      
          return doctor_matches
      
      
      # 用户输入医生和医院的偏好
      doctors = {}
      hospitals = {}
      
      n_doctors = int(input("请输入医生人数:"))
      n_hospitals = int(input("请输入医院数量:"))
      
      for i in range(n_doctors):
          doctor_name = input(f"请输入第{i+1}位医生的姓名:")
          doctor_preferences = input(f"请输入{doctor_name}医生对医院的偏好(以空格分隔):").split()
          doctors[doctor_name] = doctor_preferences
      
      for i in range(n_hospitals):
          hospital_name = input(f"请输入第{i+1}家医院的名称:")
          hospital_preferences = input(f"请输入{hospital_name}医院对医生的偏好(以空格分隔):").split()
          hospitals[hospital_name] = hospital_preferences
      
      # 调用稳定婚姻算法
      matches = stable_marriage(doctors, hospitals)
      
      # 输出医生-医院匹配结果
      for doctor, hospital in matches.items():
          print(f"{doctor} 匹配到 {hospital}")
      

      4.动态规划

      动态规划(Dynamic Programming)是一种优化问题求解的算法思想,适用于具有重叠子问题和最优子结构性质的问题。它将问题分解为一系列重叠的子问题,并通过保存子问题的解来避免重复计算,从而实现对整个问题的高效求解。

      动态规划算法通常遵循以下步骤:

      1. 确定状态:将原问题划分为若干个子问题,并定义状态表示问题的解。

      2. 定义状态转移方程:通过递推关系式来描述子问题之间的关系,即如何通过已知的子问题的解来计算当前问题的解。

      3. 确定初始条件:确定最简单的子问题的解,作为递推的起点。

      4. 确定计算顺序:根据子问题之间的依赖关系,确定计算的顺序,通常采用自底向上的方式进行计算。

      5. 计算最优解:依据状态转移方程,按照确定的计算顺序,通过递推计算出问题的最优解。

      6. 构造最优解:根据计算得到的最优解和保存的状态信息,构造出原问题的最优解。

      动态规划算法的核心思想是利用子问题的解来求解更大规模的问题,通过保存子问题的解,避免了重复计算,从而显著提高了算法的效率。动态规划常用于求解最优化问题,如最短路径问题、背包问题、序列比对等。

      经典动态规划算法:接缝雕刻;文本相似和不同比较;样条曲线的赋值等。

      以下是一些动态规划常用于解决的经典问题:

      1. Fibonacci 数列:计算第 n 个 Fibonacci 数的值。
      2. 背包问题(Knapsack Problem):在给定容量的背包中,选择一些物品放入背包,使得物品的总价值最大化,同时不超过背包的容量。
      3. 最长公共子序列(Longest Common Subsequence):给定两个字符串,找到它们的最长公共子序列的长度。
      4. 最长递增子序列(Longest Increasing Subsequence):给定一个序列,找到一个最长的子序列,使得子序列中的元素按顺序递增。
      5. 矩阵链乘法(Matrix Chain Multiplication):给定一系列矩阵,通过合理地加括号,使得矩阵相乘的次数最少。
      6. 最短路径问题(Shortest Path Problem):在带有权重的有向图中,找到从起点到终点的最短路径。
      7. 最大子数组和(Maximum Subarray Sum):给定一个整数数组,找到一个具有最大和的连续子数组。
      8. 最长回文子串(Longest Palindromic Substring):给定一个字符串,找到一个最长的回文子串。
      9. 编辑距离(Edit Distance):计算将一个字符串转换为另一个字符串所需的最少编辑操作次数。
      10. 切割钢条(Cutting Rod):将一根长度为 n 的钢条切割成若干段,使得卖出的总价值最大化。

      1.加权区间调度

      问题描述:

      作业j从 s j s_{j} sj​开始,在 f j f_{j} fj​结束,且每个作业有个权重 w j w_{j} wj​

      如果两个作业不重叠,则它们是兼容的。

      目标:找到相互兼容作业且权重最大的子集。

      解题思路:

      当解决加权区间调度问题时,我们希望找到一组相容的区间,使得它们的总权重和最大。

      动态规划是一种常用的解决最优化问题的方法。在解决加权区间调度问题时,我们可以利用动态规划的思想来逐步计算出最优解。

      首先,我们将所有的区间按照结束时间从小到大进行排序。这是因为结束时间早的区间有更大的潜力可以和后面的区间相容。

      接下来,我们定义一个dp数组,dp[i]表示以第i个区间为最后一个区间时的最大权重和。我们需要逐个计算dp数组的值。

      对于每个区间i,我们需要考虑两种情况:

      1. 区间i不被选中:此时dp[i]等于dp[i-1],即前一个区间为最后一个区间时的最大权重和。
      2. 区间i被选中:此时我们需要找到前面结束时间小于等于区间i开始时间的区间j,使得dp[j]+区间i的权重最大。因此,我们需要遍历前面的区间j,找到这样的区间,并计算dp[j]+区间i的权重。

      最后,我们将dp[i]更新为这两种情况中的较大值,即dp[i] = max(dp[i-1], dp[j]+区间i的权重)。

      通过这样的状态转移,我们可以逐个计算dp数组的值。最终,dp数组的最后一个元素即为最大权重和。

      总结一下动态规划解决加权区间调度的思路:

      1. 将所有区间按照结束时间从小到大进行排序。
      2. 定义dp数组,长度为区间个数,初始化为0。
      3. 遍历每个区间i,计算dp[i]的值:
        a. 如果区间i不被选中,dp[i]等于dp[i-1]。
        b. 如果区间i被选中,找到前面结束时间小于等于区间i开始时间的区间j,计算dp[j]+区间i的权重。
      4. 将dp[i]更新为上述两种情况中的较大值。
      5. 返回dp数组的最后一个元素,即为最大权重和。

      希望这样的解题思路能够帮助你更好地理解动态规划解决加权区间调度问题的思路。

      python代码实现:

      class Job:
          def __init__(self, start, end, weight):
              self.start = start
              self.end = end
              self.weight = weight
      
      
      def weighted_interval_scheduling(jobs):
          jobs.sort(key=lambda x: x.end)  # 按照结束时间从小到大排序
          n = len(jobs)
          dp = [0] * n
          dp[0] = jobs[0].weight  # 初始化第一个作业的dp值为其权重
      
          for i in range(1, n):
              dp[i] = jobs[i].weight  # 初始化dp[i]为作业i的权重
              for j in range(i-1, -1, -1):
                  if jobs[j].end <= jobs[i].start:
                      dp[i] = max(dp[i], dp[j] + jobs[i].weight)  # 更新dp[i]的值
      
          return max(dp)  # 返回最大权重和
      
      # 示例输入
      jobs = [
          Job(1, 4, 3),
          Job(3, 5, 2),
          Job(0, 6, 4),
          Job(4, 7, 1),
          Job(3, 8, 2),
          Job(5, 9, 6),
          Job(6, 10, 4),
          Job(8, 11, 2)
      ]
      
      # 输出最大权重和
      print(weighted_interval_scheduling(jobs))
      

      2.最大子数组问题

      问题描述:
      最大子数组问题是指在一个数组中,找到一个连续子数组,使得该子数组的和最大。

      思路分析:

      下面是使用动态规划解决最大子数组问题的一般思路:

      1. 定义一个dp数组,长度与原数组相同,用于存储以当前位置为结尾的最大子数组和。
      2. 初始化dp数组的第一个元素为原数组的第一个元素,即dp[0] = nums[0]。
      3. 从位置1开始遍历原数组,计算以当前位置为结尾的最大子数组和。
        • 如果dp[i-1]大于0,说明以前一个位置为结尾的最大子数组和对于当前位置的子数组和是有贡献的,因此dp[i] = dp[i-1] + nums[i]。
        • 如果dp[i-1]小于等于0,说明以前一个位置为结尾的最大子数组和对于当前位置的子数组和没有贡献,因此dp[i] = nums[i]。
      4. 遍历dp数组,找到最大的子数组和,即max_sum = max(dp)。
      5. 返回max_sum,即为最大子数组和。

      python代码实现:

      def max_subarray(nums):
          n = len(nums)
          if n == 0:
              return 0
      
          max_sum = nums[0]  # 初始化最大子数组和为第一个元素
          curr_sum = nums[0]  # 当前位置的最大子数组和
      
          for i in range(1, n):
              if curr_sum > 0:
                  curr_sum += nums[i]
              else:
                  curr_sum = nums[i]
      
              max_sum = max(max_sum, curr_sum)
      
          return max_sum
      
      # 用户输入和数据验证
      while True:
          try:
              nums = [int(x) for x in input("请输入一个整数数组,数字之间用空格分隔:").split()]
              break
          except ValueError:
              print("输入无效,请重新输入整数数组!")
      
      # 输出最大子数组和
      print(max_subarray(nums))
      

      在这个题的基础上,引申出一个新的题目:

      goal:given an n-by-n matrix,find a rectangle whose sum is maxinum

      要使用动态规划求解给定的 n × n 矩阵中和最大的矩形,可以按照以下步骤进行:

      1. 定义一个 dp 数组,其大小为 n × n,用于存储以矩阵中每个位置为右下角的矩形的和。
      2. 初始化 dp 数组的第一行和第一列为矩阵的第一行和第一列元素。
      3. 从第二行和第二列开始,遍历矩阵中的每个位置 (i, j):
        • 对于每个位置,计算以该位置为右下角的矩形的和,即 d p [ i ] [ j ] = d p [ i − 1 ] [ j ] + d p [ i ] [ j − 1 ] − d p [ i − 1 ] [ j − 1 ] + m a t r i x [ i ] [ j ] dp[i][j] = dp[i-1][j] + dp[i][j-1] - dp[i-1][j-1] + matrix[i][j] dp[i][j]=dp[i−1][j]+dp[i][j−1]−dp[i−1][j−1]+matrix[i][j]。
      4. 遍历 dp 数组,找到最大的矩形和。
      5. 返回最大的矩形和。

      python代码实现:

      def max_rectangle_sum(matrix):
          n = len(matrix)
          if n == 0:
              return 0
          
          dp = [[0] * n for _ in range(n)]  # 定义 dp 数组
          
          # 初始化第一行和第一列
          dp[0][0] = matrix[0][0]
          for i in range(1, n):
              dp[i][0] = dp[i-1][0] + matrix[i][0]
              dp[0][i] = dp[0][i-1] + matrix[0][i]
          
          # 计算 dp 数组
          for i in range(1, n):
              for j in range(1, n):
                  dp[i][j] = dp[i-1][j] + dp[i][j-1] - dp[i-1][j-1] + matrix[i][j]
          
          max_sum = float('-inf')  # 初始化最大矩形和为负无穷大
          
          # 遍历 dp 数组,找到最大矩形和
          for i in range(n):
              for j in range(n):
                  for k in range(i, n):
                      for l in range(j, n):
                          curr_sum = dp[k][l]
                          if i > 0:
                              curr_sum -= dp[i-1][l]
                          if j > 0:
                              curr_sum -= dp[k][j-1]
                          if i > 0 and j > 0:
                              curr_sum += dp[i-1][j-1]
                          max_sum = max(max_sum, curr_sum)
          
          return max_sum
      
      # 示例输入
      matrix = [
          [1, 2, -1],
          [-3, 0, 6],
          [7, 8, -9]
      ]
      
      # 输出最大矩形和
      print(max_rectangle_sum(matrix))
      

      3.背包问题

      问题描述:

      背包问题是一个经典的组合优化问题,旨在从一组物品中选择适合放入背包以最大化总价值,同时要求背包的容量不超过给定的限制。

      实现思路:

      1. 定义一个一维数组 dp,大小为 (W+1),其中 W 是背包的容量。dp[j] 表示背包容量为 j 时的最大价值。
      2. 初始化 dp 数组为 0,即 dp[j] = 0。
      3. 从位置 1 开始遍历 dp 数组,并计算每个位置的最大价值。
        • 对于每个位置 j,我们需要判断当前物品的重量是否小于等于背包容量 j。如果是,则可以选择将该物品放入背包中,此时的最大价值为 max(dp[j], dp[j-w] + v),其中 w 是当前物品的重量,v 是当前物品的价值。
        • 我们将计算得到的最大价值更新到 dp[j] 中。
      4. 遍历完整个 dp 数组后,dp[W] 即为最大的背包价值。
      5. 可以通过回溯 dp 数组,找到放入背包的物品。
        • 我们从最后一个位置 W 开始,如果 dp[j] != dp[j-w] + v,表示第 j 个物品被放入背包中。
        • 然后,我们将 j 减去该物品的重量,继续向前搜索。
        • 重复上述步骤,直到搜索到第一个位置 1,即可得到放入背包的物品。
      6. 返回最大价值和放入背包的物品。

      python代码实现:

      def knapsack_dp(weight, value, capacity):
          n = len(weight)
          if n == 0 or capacity == 0:
              return 0, []
      
          # 将浮点数转换为整数,乘以一个大的倍数,以保留小数点后的精度
          multiplier = 100
          weight = [int(w * multiplier) for w in weight]
          capacity = int(capacity * multiplier)
      
          dp = [0] * (capacity + 1)
          picks = []
      
          for i in range(n):
              if weight[i] <= capacity:
                  for j in range(capacity, weight[i] - 1, -1):
                      if dp[j] < dp[j - weight[i]] + value[i]:
                          dp[j] = dp[j - weight[i]] + value[i]
      
          max_value = dp[capacity]
      
          # 回溯找到放入背包的物品
          j = capacity
          for i in range(n - 1, -1, -1):
              if j >= weight[i] and dp[j] == dp[j - weight[i]] + value[i]:
                  picks.append(i)
                  j -= weight[i]
      
          picks.reverse()
      
          return max_value, picks
      
      
      # 输入数据
      n = int(input("请输入物品数量:"))
      weight = []
      value = []
      for i in range(n):
          w = float(input(f"请输入第 {i+1} 个物品的重量:"))
          v = float(input(f"请输入第 {i+1} 个物品的价值:"))
          weight.append(w)
          value.append(v)
      capacity = float(input("请输入背包的容量:"))
      
      # 数据合法性验证
      if n <= 0 or capacity < 0:
          print("输入的物品数量或背包容量不合法,请重新输入!")
      else:
          max_value, picks = knapsack_dp(weight, value, capacity)
          print("最大价值为:", max_value)
          print("放入背包的物品索引:", picks)
      

      4.最长公共子序列问题

      问题描述:

      给定两个字符串,要求找到它们的最长公共子序列的长度。

      解题思路:

      1. 定义问题:
        • 输入:两个字符串 s1 和 s2。
        • 输出:最长公共子序列的长度。
      2. 创建一个二维数组 dp,大小为 (len(s1)+1) × (len(s2)+1),用来保存最长公共子序列的长度。
        • dp[i][j] 表示字符串 s1 的前 i 个字符和字符串 s2 的前 j 个字符的最长公共子序列的长度。
      3. 初始化边界条件:
        • 当 i=0 或 j=0 时,dp[i][j] = 0,表示一个字符串为空时,最长公共子序列的长度为 0。
      4. 动态规划计算最长公共子序列的长度:
        • 从 i=1 和 j=1 开始,逐步计算 dp[i][j]。
        • 如果 s1[i-1] 等于 s2[j-1],则这两个字符可以加入最长公共子序列中,即 dp[i][j] = dp[i-1][j-1] + 1。
        • 如果 s1[i-1] 不等于 s2[j-1],则需要在 s1 的前 i-1 个字符和 s2 的前 j 个字符中找到最长公共子序列,或者在 s1 的前 i 个字符和 s2 的前 j-1 个字符中找到最长公共子序列,取两者中的较大值,即 dp[i][j] = max(dp[i-1][j], dp[i][j-1])。
      5. 返回最长公共子序列的长度:
        • dp[len(s1)][len(s2)] 即为最长公共子序列的长度。

      python代码:

      def longest_common_subsequence(s1, s2):
          m = len(s1)
          n = len(s2)
      
          # 创建一个二维数组来保存最长公共子序列的长度
          dp = [[0] * (n + 1) for _ in range(m + 1)]
      
          # 动态规划计算最长公共子序列的长度
          for i in range(1, m + 1):
              for j in range(1, n + 1):
                  if s1[i - 1] == s2[j - 1]:
                      dp[i][j] = dp[i - 1][j - 1] + 1
                  else:
                      dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
      
          # 返回最长公共子序列的长度
          return dp[m][n]
      
      
      # 用户输入和数据验证
      s1 = input("请输入第一个字符串:")
      s2 = input("请输入第二个字符串:")
      
      if not s1 or not s2:
          print("输入字符串不能为空")
      else:
          lcs_length = longest_common_subsequence(s1, s2)
          print("最长公共子序列的长度为:", lcs_length)
      
      版权声明:本文内容来自第三方投稿或授权转载,原文地址:https://lglxv587.blog.csdn.net/article/details/134295830,作者:散一世繁华,颠半世琉璃,版权归原作者所有。本网站转在其作品的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如因作品内容、版权等问题需要同本网站联系,请发邮件至ctyunbbs@chinatelecom.cn沟通。

      上一篇:数学建模算法与应用 第1章 线性规划

      下一篇:网络流探索:解决网络最大流问题的算法集锦

      相关文章

      2025-05-19 09:04:14

      复杂度的OJ练习

      复杂度的OJ练习

      2025-05-19 09:04:14
      代码 , 复杂度 , 思路 , 数组 , 算法
      2025-05-16 09:15:24

      jQuery遍历对象、数组、集合

      jQuery遍历对象、数组、集合

      2025-05-16 09:15:24
      jQuery , 对象 , 数组 , 遍历 , 集合
      2025-05-16 09:15:24

      如何将一串数字用函数的方法倒过来(C语言)

      如何将一串数字用函数的方法倒过来(C语言)

      2025-05-16 09:15:24
      函数 , 数字 , 数组
      2025-05-16 09:15:17

      递归,搜索,回溯算法(3)之穷举,暴搜,深搜,回溯,剪枝

      递归,搜索,回溯算法(3)之穷举,暴搜,深搜,回溯,剪枝

      2025-05-16 09:15:17
      回溯 , 子集 , 数组 , 算法 , 递归
      2025-05-14 10:33:31

      计算机小白的成长历程——数组(1)

      计算机小白的成长历程——数组(1)

      2025-05-14 10:33:31
      strlen , 个数 , 元素 , 内存 , 十六进制 , 地址 , 数组
      2025-05-14 10:33:31

      计算机小白的成长历程——习题演练(函数篇)

      计算机小白的成长历程——习题演练(函数篇)

      2025-05-14 10:33:31
      函数 , 字符串 , 数组 , 知识点 , 编写 , 迭代 , 递归
      2025-05-14 10:02:48

      typescript 将数组清空

      在TypeScript或JavaScript开发中,数组是用于存储和管理一组数据的基础数据结构。当需要清空一个数组时,有多种方法可以实现,而选择合适的方法不仅影响代码的可读性,还会对性能产生一定的影响。不同场景下,选择适合的清空数组的方法至关重要。

      2025-05-14 10:02:48
      length , pop , 引用 , 数组 , 方法
      2025-05-13 09:50:28

      Java 两个小时以后

      最大正方形在一个由 '0' 和 '1' 组成的二维矩阵内,找到只包含 '1' 的最大正方形,并返回其面积。 

      2025-05-13 09:50:28
      length , matrix , nums , target , 数组
      2025-05-13 09:50:17

      java实现167. 两数之和 II - 输入有序数组

      给你一个下标从 1 开始的整数数组 numbers ,该数组已按 非递减顺序排列  ,请你从数组中找出满足相加之和等于目标数 target 的两个数。

      2025-05-13 09:50:17
      target , 两个 , 数组 , 整数
      2025-05-13 09:50:17

      java实现6. Z 字形变换

      将一个给定字符串 s 根据给定的行数 numRows ,以从上往下、从左到右进行 Z 字形排列。

      2025-05-13 09:50:17
      字符 , 字符串 , 数组
      查看更多
      推荐标签

      作者介绍

      天翼云小翼
      天翼云用户

      文章

      33561

      阅读量

      5225031

      查看更多

      最新文章

      递归,搜索,回溯算法(3)之穷举,暴搜,深搜,回溯,剪枝

      2025-05-16 09:15:17

      DS初阶:二叉树的顺序结构及堆的实现

      2025-05-08 09:04:49

      【30天玩转python】数据分析与可视化

      2025-05-06 09:19:30

      蓝桥杯算法竞赛系列第九章·巧解哈希题,用这3种数据类型足矣

      2025-04-22 09:27:17

      文心一言 VS 讯飞星火 VS chatgpt (358)-- 算法导论24.2 4题

      2025-04-16 09:12:36

      文心一言 VS 讯飞星火 VS chatgpt (22)-- 算法导论4.2 2题

      2025-04-01 10:29:12

      查看更多

      热门文章

      前端项目实战66-数组数据处理详解

      2023-05-12 06:47:16

      20.6.4算法心得(数组运用)

      2023-03-21 10:39:47

      字节输入流读数据 使用字节数组

      2023-03-29 09:42:23

      把一个数组(列表)中的数据逆向反转,python

      2023-04-13 09:31:18

      算法问题-五行缺数

      2022-12-26 09:32:17

      算法问题-删除k个数字是num最小

      2022-12-26 09:32:17

      查看更多

      热门标签

      算法 leetcode python 数据 java 数组 节点 大数据 i++ 链表 golang c++ 排序 django 数据类型
      查看更多

      相关产品

      弹性云主机

      随时自助获取、弹性伸缩的云服务器资源

      天翼云电脑(公众版)

      便捷、安全、高效的云电脑服务

      对象存储

      高品质、低成本的云上存储服务

      云硬盘

      为云上计算资源提供持久性块存储

      查看更多

      随机文章

      给你一棵 二叉树 的根节点 root ,树中有 n 个节点 每个节点都可以被分配一个从 1 到 n 且互不相同的值

      二狗买了一些小兵玩具,和大胖一起玩, 一共有n个小兵,这n个小兵拍成一列, 第i个小兵战斗力为hi,然后他们两个开始对小兵进行排列

      给定一个正整数组成的无序数组arr,给定一个正整数值K,找到arr的所有子数组里,哪个子数组的累加和等于K并且是长度最大的。返回其长度。

      薯队长从北向南穿过一片红薯地(南北长M,东西宽N),红薯地被划分为1x1的方格, 他可以从北边的任何一个格子出发,到达南边的任何一个格子。

      无序数组arr,子数组-1和1的数量一样多,请问最长子数组的长度是多少?

      打砖块。有一个 m x n 的二元网格,其中 1 表示砖块,0 表示空白。

      • 7*24小时售后
      • 无忧退款
      • 免费备案
      • 专家服务
      售前咨询热线
      400-810-9889转1
      关注天翼云
      • 旗舰店
      • 天翼云APP
      • 天翼云微信公众号
      服务与支持
      • 备案中心
      • 售前咨询
      • 智能客服
      • 自助服务
      • 工单管理
      • 客户公告
      • 涉诈举报
      账户管理
      • 管理中心
      • 订单管理
      • 余额管理
      • 发票管理
      • 充值汇款
      • 续费管理
      快速入口
      • 天翼云旗舰店
      • 文档中心
      • 最新活动
      • 免费试用
      • 信任中心
      • 天翼云学堂
      云网生态
      • 甄选商城
      • 渠道合作
      • 云市场合作
      了解天翼云
      • 关于天翼云
      • 天翼云APP
      • 服务案例
      • 新闻资讯
      • 联系我们
      热门产品
      • 云电脑
      • 弹性云主机
      • 云电脑政企版
      • 天翼云手机
      • 云数据库
      • 对象存储
      • 云硬盘
      • Web应用防火墙
      • 服务器安全卫士
      • CDN加速
      热门推荐
      • 云服务备份
      • 边缘安全加速平台
      • 全站加速
      • 安全加速
      • 云服务器
      • 云主机
      • 智能边缘云
      • 应用编排服务
      • 微服务引擎
      • 共享流量包
      更多推荐
      • web应用防火墙
      • 密钥管理
      • 等保咨询
      • 安全专区
      • 应用运维管理
      • 云日志服务
      • 文档数据库服务
      • 云搜索服务
      • 数据湖探索
      • 数据仓库服务
      友情链接
      • 中国电信集团
      • 189邮箱
      • 天翼企业云盘
      • 天翼云盘
      ©2025 天翼云科技有限公司版权所有 增值电信业务经营许可证A2.B1.B2-20090001
      公司地址:北京市东城区青龙胡同甲1号、3号2幢2层205-32室
      • 用户协议
      • 隐私政策
      • 个人信息保护
      • 法律声明
      备案 京公网安备11010802043424号 京ICP备 2021034386号