2021年中国大学生程序设计竞赛女生专场C. 连锁商店

本文介绍了2021年中国大学生程序设计竞赛女生专场的一道题目,涉及连锁商店的动态规划解决方案。通过将公司分为两类,利用状态压缩动态规划进行求解,时间复杂度为O(nn2^(n/2))。文章详细分析了如何重新分类公司,定义状态转移方程,并提供了拓扑序遍历的AC代码。
摘要由CSDN通过智能技术生成

题目链接:传送门

官方思路:
如果某家公司开的连锁店数量不超过 1,那么可以无视 “每家公司的红包只能领一份” 这个限制,这是因为任何一条路线都无法访问多次该公司开的商店。如果某家公司开的连锁店数量至少为 2,那么这样的公司数最多为 n/2 ≤18。
由于第二类公司数量并不多,因此可以使用状态压缩动态规划来求解这个问题。设f[i][S]表示从 1 出发到达了 i 点,一路上访问过的第二类公司集合为 S 时,访问过的第一类公司的红包总价值最大是多少,枚举下一个景点进行转移。时间复杂度 O(nn2^(n/2) )。

具体分析:
先将每家公司重新分类,
连锁店不超过1家(<=1)的作为第一类,并将其赋为编号-1(表示是第一类);
连锁店超过一家(>=2)的作为第二类,并对所有的第二类公司(共kind个)重新编号从0到kind-1。

    for(int i=1;i<=n;i++){
   
        scanf("%d",&c[i]);
        vis[c[i]]++;
    }
    for(int i=1;i<=n;i++){
     ///公司的分类
        if(vis[i]>=2) num[i] = kind++;
        else num[i] = -1;
    }

而后开始写状态转移dp[pre][S]到dp[now][S]的转移
若pre到now之间有一条缆车,则可以从pre的状态转移到now的状态,此时需要讨论该景点的商店所属公司是否为第一类,即num[c[now]]是否为-1。
具体讨论见代码:

void dfs(int now,int pre)
{
   
    if(num[c[now]]==-1) {
    ///第一类直接加上
        for(int i=0;i<(1<<kind);i++){
   
            dp[now][i] = max(dp[now][i],dp[pre][i] + w[c[now]]); ///直接继承以前的状态
            dp[now][(1<<kind)] = max(dp[now][(1<<kind)],dp[now][i]); ///dp[now][(1<<kind)]储存1到now的可以获得的最大值
        }
    }
    else {
    ///第二类选择转移
        for(int i=0;i<(1<<kind);i++){
   
            int t1 = (1<<num[c[now]]);  ///表示要选择该位置,1<<num[c[now]]为该位置在S中对应的二进制位置
            if(t1&i){
     ///若t1&i!=0则表示当pre的状态为i时该公司的优惠券已经被选择
                dp
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值