题解 | #基因序列分组优化#

基因序列分组优化

https://www.nowcoder.com/practice/cbd06a6fb93d4970ab57d83a5e885acd

REALHW90 基因序列分组优化

题目链接

基因序列分组优化

题目描述

在一个基因工程研究项目中,科学家们获得了一批基因序列样本 。这批样本的数量为 ,其中 是一个偶数。每个基因序列都有一个整数ID。为了进行对比实验,需要将这批样本 分成两个小组:实验组 和对照组

分组必须遵循以下严格的实验标准:

  1. 数量均等: 两个小组的基因序列样本数量必须完全相等,即
  2. 组内ID唯一性: 在同一个小组内,所有基因序列的ID必须是唯一的。
  3. 有序排列: 输出时,两个小组内的基因序列ID都必须按升序排列。
  4. 实验组复杂度最小化: 实验组 的“基因复杂度”(定义为组内所有ID的总和)必须达到最小值。

您的任务是设计一个算法,根据给定的初始样本集合 ,找出满足上述所有条件的最优分组方案。

解题思路

这是一个分组优化问题,其核心在于如何在满足约束条件的前提下找到最优解。通过分析题目要求,可以发现这是一个典型的贪心问题。解决策略可以分为三步:处理无解情况、处理必须的强制分配、对剩余部分进行贪心选择。

  1. 预处理与无解情况判断 首先,我们需要统计每个ID的出现频率。根据“组内ID唯一性”的规则,任何一个ID在单个组内最多只能出现一次。由于我们只有两个组,所以任何ID在总样本中最多只能出现两次。如果一个ID出现了三次或更多次,根据鸽巢原理,必然至少有两个相同的ID被分到同一组,从而违反规则。因此,如果任何ID的出现次数大于2,则问题无解,直接输出null

  2. 确定性分配(强制分配) 对于那些出现次数恰好为2次的ID(我们称之为“成对ID”),它们必须被分到不同的组中才能满足唯一性。因此,我们可以直接将每个成对ID的一个副本放入实验组,另一个副本放入对照组。这部分的分配是没有选择余地的,是确定性的。

  3. 贪心选择(优化分配) 处理完成对ID后,剩下的都是只出现了1次的ID(我们称之为“单一ID”)。这些ID是我们进行优化分配的部分。题目要求最小化实验组的ID总和。由于成对ID对两组总和的贡献是相同的,所以为了实现这一目标,我们应该将值最小的单一ID分配给实验组。 具体做法是: a. 将所有单一ID收集起来并按升序排序。 b. 将排序后前半部分的单一ID全部分配给实验组。 c. 将排序后后半部分的单一ID全部分配给对照组

  4. 输出 完成所有分配后,分别对实验组和对照组的最终ID列表进行升序排序,然后按格式要求输出。

代码

#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
#include <string>
#include <sstream>

using namespace std;

void print_vector(const vector<int>& vec) {
    for (size_t i = 0; i < vec.size(); ++i) {
        cout << vec[i] << (i == vec.size() - 1 ? "" : " ");
    }
    cout << endl;
}

int main() {
    string line;
    getline(cin, line);
    if (line.empty()) {
        cout << "null" << endl;
        return 0;
    }
    
    stringstream ss(line);
    vector<int> ids;
    int num;
    while (ss >> num) {
        ids.push_back(num);
    }
    
    map<int, int> counts;
    for (int id : ids) {
        counts[id]++;
    }

    for (auto const& [id, count] : counts) {
        if (count > 2) {
            cout << "null" << endl;
            return 0;
        }
    }

    vector<int> group_a;
    vector<int> group_b;
    vector<int> singles;

    for (auto const& [id, count] : counts) {
        if (count == 2) {
            group_a.push_back(id);
            group_b.push_back(id);
        } else {
            singles.push_back(id);
        }
    }

    // singles 已经是按键(ID)排序的
    int num_singles_for_a = singles.size() / 2;
    for (int i = 0; i < num_singles_for_a; ++i) {
        group_a.push_back(singles[i]);
    }
    for (size_t i = num_singles_for_a; i < singles.size(); ++i) {
        group_b.push_back(singles[i]);
    }

    sort(group_a.begin(), group_a.end());
    sort(group_b.begin(), group_b.end());

    print_vector(group_a);
    print_vector(group_b);

    return 0;
}
import java.util.*;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String line = sc.nextLine();
        
        if (line == null || line.trim().isEmpty()) {
            System.out.println("null");
            return;
        }

        String[] parts = line.split("\\s+");
        List<Integer> ids = new ArrayList<>();
        for (String part : parts) {
            ids.add(Integer.parseInt(part));
        }

        Map<Integer, Integer> counts = new HashMap<>();
        for (int id : ids) {
            counts.put(id, counts.getOrDefault(id, 0) + 1);
        }

        for (int count : counts.values()) {
            if (count > 2) {
                System.out.println("null");
                return;
            }
        }

        List<Integer> groupA = new ArrayList<>();
        List<Integer> groupB = new ArrayList<>();
        List<Integer> singles = new ArrayList<>();

        List<Integer> sortedKeys = new ArrayList<>(counts.keySet());
        Collections.sort(sortedKeys);

        for (int id : sortedKeys) {
            if (counts.get(id) == 2) {
                groupA.add(id);
                groupB.add(id);
            } else {
                singles.add(id);
            }
        }

        int numSinglesForA = singles.size() / 2;
        for (int i = 0; i < numSinglesForA; i++) {
            groupA.add(singles.get(i));
        }
        for (int i = numSinglesForA; i < singles.size(); i++) {
            groupB.add(singles.get(i));
        }

        Collections.sort(groupA);
        Collections.sort(groupB);

        System.out.println(groupA.stream().map(String::valueOf).collect(Collectors.joining(" ")));
        System.out.println(groupB.stream().map(String::valueOf).collect(Collectors.joining(" ")));
    }
}
from collections import Counter

def solve():
    line = input()
    if not line:
        print("null")
        return
        
    ids = list(map(int, line.split()))
    
    counts = Counter(ids)
    
    if any(count > 2 for count in counts.values()):
        print("null")
        return
        
    group_a = []
    group_b = []
    singles = []
    
    # 对ID进行排序以保证处理顺序,从而使singles列表自然有序
    for id_val in sorted(counts.keys()):
        if counts[id_val] == 2:
            group_a.append(id_val)
            group_b.append(id_val)
        else:
            singles.append(id_val)
            
    num_singles_for_a = len(singles) // 2
    
    group_a.extend(singles[:num_singles_for_a])
    group_b.extend(singles[num_singles_for_a:])
    
    group_a.sort()
    group_b.sort()
    
    print(*group_a)
    print(*group_b)

solve()

算法及复杂度

  • 算法: 贪心算法
  • 时间复杂度: ,其中 是基因序列的总数。时间复杂度的瓶颈主要在于对所有唯一的ID进行排序,或者在最后对两个分组结果进行排序。频率统计本身的时间复杂度为
  • 空间复杂度: ,其中 是不同ID的数量()。主要用于存储ID的频率映射以及最终的分组列表。
全部评论

相关推荐

头像
03-03 15:53
已编辑
黑龙江大学 Java
在当前开源项目极为丰富的背景下,付费资源并不一定意味着最前沿的技术优势,在具体执行层面展示出自己的独特价值,才是简历上最重要的加分项。1.&nbsp;WebMCP&nbsp;—&nbsp;让网站主动告诉&nbsp;AI&nbsp;该怎么操作AI&nbsp;操作浏览器的方案一直靠&quot;猜&quot;——截图识别、DOM&nbsp;解析,错误率&nbsp;15-30%。WebMCP&nbsp;反过来,让网站自己声明能做什么,AI&nbsp;直接调用结构化接口,准确率接近&nbsp;100%。Chrome&nbsp;Canary&nbsp;已实装。企业内部系统的&nbsp;WebMCP&nbsp;适配目前几乎没人做,是明确的蓝海。推荐理由:简历上写的不是&quot;我会用某个框架&quot;,而是&quot;我在标准刚发布时就做了企业适配&...
书海为家:#人脑vsAI# 尽管深度学习的最初灵感来源于人类的大脑,但二者的运作方式截然不同:深度学习所需要的数据量远比人脑所需要的多得多。可是一旦经过大数据训练,它在相同领域的表现将远远超过人类(尤其是在数字的量化学习,例如挑选某人最可能购买的产品,或从100万张脸中挑选最匹配的一张)——相对来说,人类在同一时间内只能把注意力放在少数几件事情上面,而深度学习算法却可以同时处理海量信息,并且发现在大量数据背后的模糊特征之间的关联,这些模糊特征不仅复杂而且微妙,人类往往无法理解,甚至可能不会注意到。 虽然深度学习拥有人类所缺乏的并行处理海量数据的“绝技”,但不具备人类在面对决策时独一无二的汲取过去的经验、使用抽象概念和常识的能力。 与人类相比,深度学习想要充分发挥作用,离不开海量的相关数据、单一领域的应用场景以及明确的目标函数,这三项缺一不可,如果缺少其中任何一项,深度学习将无用武之地。
AI求职实录
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务