首页 > 试题广场 >

全民健身季推荐网络与积分衰减计算

[编程题]全民健身季推荐网络与积分衰减计算
  • 热度指数:28 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解

背景
为了响应“全民健身”号召,某大型连锁健身房在2025年上半年推出了一项“老带新”裂变营销活动。现有会员可以推荐新会员入会,新会员入会后也可以继续推荐其他人。为了鼓励会员积极推荐,健身房不仅会给直接推荐人发放积分,还会给间接推荐人发放积分,但积分会随着推荐层级的加深而发生衰减。现在,健身房店长希望追溯某位活跃会员在特定活动期间建立的完整推荐网络,并核算其网络中每个节点为其贡献的实际积分。

表结构和字段说明

  • 表名:members(健身房会员表)
    • member_id:整数类型,会员的唯一编号,主键
    • member_name:字符串类型,会员的真实姓名
    • membership_type:字符串类型,办理的会员卡类型(如年卡、私教包月卡等)
  • 表名:referral_records(会员推荐记录表)
    • referrer_id:整数类型,推荐人编号(老会员)
    • referee_id:整数类型,被推荐人编号(新入会会员)
    • join_date:日期类型,新会员正式签约入会的日期
    • base_reward_points:浮点数类型,该次推荐产生的基础奖励积分(根据新会员办卡金额不同,基础积分不同)

3. 问题

请编写一条 MySQL 查询语句,查出由名为'张三'的会员直接或间接推荐入会的所有下线会员。

任务要求:

  1. 时间限制:仅统计新会员入会日期(join_date)在 2025-01-01 至 2025-06-30(包含首尾两日)期间的推荐记录。注意:递归网络中的每一次推荐关系都必须发生在此时段内,否则该分支将被截断。
  2. 字段与计算要求:需要返回以下4个字段:
    • referee_id:被推荐人编号
    • referee_name:被推荐人姓名
    • referral_level:推荐层级(直接推荐的层级为1,被推荐人再推荐的层级为2,依此类推)
    • actual_points:实际贡献积分。计算公式为:基础奖励积分(base_reward_points) * POW(0.5, 推荐层级 - 1)。结果必须四舍五入保留2位小数。
  3. 排序规则
    首先按推荐层级(referral_level)升序排列;
    若层级相同,按实际贡献积分(actual_points)降序排列;
    若积分依然相同,按被推荐人编号(referee_id)升序排列。
示例1

输入

DROP TABLE IF EXISTS referral_records;
DROP TABLE IF EXISTS members;

CREATE TABLE members (
    member_id INT PRIMARY KEY,
    member_name VARCHAR(50),
    membership_type VARCHAR(50)
);

CREATE TABLE referral_records (
    referrer_id INT,
    referee_id INT,
    join_date DATE,
    base_reward_points DECIMAL(10, 2)
);

-- 插入示例数据
INSERT INTO members (member_id, member_name, membership_type) VALUES
(1001, '张三', '年度VIP卡'),
(1002, '李四', '半年卡'),
(1003, '王五', '私教包月卡'),
(1004, '赵六', '季度卡'),
(1005, '孙七', '年度VIP卡'),
(1006, '周八', '次卡');

INSERT INTO referral_records (referrer_id, referee_id, join_date, base_reward_points) VALUES
(1001, 1002, '2025-02-15', 100.00), -- 张三直接推荐李四 (层级1,符合时间)
(1001, 1003, '2025-03-10', 120.00), -- 张三直接推荐王五 (层级1,符合时间)
(1002, 1004, '2025-04-05', 200.00), -- 李四推荐赵六 (层级2,符合时间)
(1004, 1005, '2025-05-20', 100.00), -- 赵六推荐孙七 (层级3,符合时间)
(1001, 1006, '2025-08-15', 500.00); -- 张三直接推荐周八 (时间超出上半年范围,应被剔除)

输出

referee_id|referee_name|referral_level|actual_points
1003|王五|1|120.0
1002|李四|1|100.0
1004|赵六|2|100.0
1005|孙七|3|25.0

说明

说明:周八(1006)入会日期在8月未被统计。李四贡献分=100\*1=100;王五贡献分=120\*1=120;赵六为层级2,贡献分=200\*0.5=100;孙七为层级3,贡献分=100\*0.25=25。层级1中王五积分高于李四,故排在李四前面
WITH RECURSIVE member_temp as (
    select a.referee_id,c.member_name,1 as referral_level,
    round(a.base_reward_points *pow(0.5,1-1),2) as actual_points
    from referral_records as a
    inner join members as b on a.referrer_id = b.member_id
    inner join members as c on a.referee_id = c.member_id
    where join_date between '2025-01-01' and '2025-06-30' and b.member_name ='张三'
    union all
    select b.referee_id,c.member_name,a.referral_level +1 as referral_level,
    round(b.base_reward_points*pow(0.5,a.referral_level),2) as actual_points
    from member_temp as a
    inner join referral_records as b on a.referee_id = b.referrer_id
    inner join members as c on b.referee_id = c.member_id
)
select referee_id,member_name as referee_name,referral_level,actual_points
from member_temp
order by referral_level asc,actual_points desc,referee_id asc
发表于 2026-03-03 22:20:56 回复(0)
with RECURSIVE temp1 as(
    select
        member_id 
        ,member_name
        ,0 as depth
    from 
        members
    where 
        member_name = '张三'
    UNION ALL
    select 
        m.member_id
        ,m.member_name
        ,temp1.depth+1 as depth
    from 
        members m 
    join referral_records r on m.member_id = r.referee_id
    join temp1 on temp1.member_id = r.referrer_id
    where 
        join_date between '2025-01-01' and '2025-06-30'
)
select
    member_id as referee_id
    ,member_name as referee_name
    ,depth as referral_level
    ,round(base_reward_points*power(0.5,depth-1),2) as actual_points
from
    temp1
join referral_records r on r.referee_id = temp1.member_id
where 
    depth > 0
order by 
    3,4 desc,1
137&138题目同解,差异点就是推荐与被推荐人互调了,cnm害老子看好久
发表于 2026-03-01 20:11:02 回复(0)