You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为特定分组图节点生成满足连接规则的唯一三元编码?

问题描述

给定整数N,存在两组对象:

  • 组1:编号1到N的对象,组内所有对象两两相连
  • 组2:编号N+1到2N的对象,组内所有对象两两相连

另有一个长度为p(1 ≤ p ≤ N²)的连接列表,每个元素为[a, b],其中a属于组1,b属于组2,表示a与b必须相连;列表中未出现的[a, b]对则不能存在连接。

需要为每个对象分配唯一的编码:

  • 编码由字符{A, B, C}组成,长度不超过M(N+1 ≤ M ≤ 3N)
  • 规则:若两个等长编码x和y存在某个索引i,使得x_i == y_i,则对应对象之间存在连接;反之,若编码在所有索引位置的字符都不相同,则对象之间无连接。

我尝试从跨组连接的编码字符入手,编写了如下代码:

#include <iostream>
#include <vector>
#include <set>

using namespace std;

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);

    int n, p, M;
    cin >> n >> p >> M;

    set<int> groups;
    set<pair<int, int>> connections;
    for (int i = 0; i < p; ++i)
    {
        int a, b;
        cin >> a >> b;

        groups.insert(b);
        connections.insert({a, b});
    }

    vector<string> codes(2 * n + 1, string(M, ' '));
    int pos = 1;
    set<int> a_pos;
    for (const int b : groups)
    {
        for (int a = 1; a <= n; ++a)
        {
            if (connections.find({a, b}) == connections.end())
                continue;

            codes[a][pos] = 'A';
            codes[b][pos] = 'A';
        }

        ++pos;
        a_pos.insert(pos);
    }
}

我的思路是:以组2的对象为端点分组处理连接,比如N=3时,若存在连接1→4、2→4,就用同一位置的'A'同时连接1、2与4,同时假设编码始终使用最大长度M。但目前无法保证所有编码的唯一性,即便注意到结构类似二分图也没有思路,该如何解决?

注:此为第三十一届波兰信息学奥林匹克(XXI Polish Olympiad in Informatics)第一轮的Satelity问题。


解决方案

要同时满足连接规则和编码唯一性,可分三部分构建编码,利用{A,B,C}的区分性覆盖所有要求:

1. 先实现组内两两相连的基础规则

组1/组2内所有对象必须两两相连,意味着组内任意两个对象的编码至少有一个位置字符相同,同时要避免组1和组2对象无意义的连接:

  • 组1所有对象的第1位设为'A',组2所有对象的第1位设为'C'——这样组1内任意两个对象在第1位字符相同,满足组内相连;且组1和组2对象在第1位无交集,不会产生额外连接
  • 组2所有对象的第2位设为'B',组1所有对象的第2位设为'C'——同理满足组2内两两相连,同时和组1对象的第2位无交集

2. 实现跨组连接的精准控制

你的分组思路可以保留,但需要优化位置分配和非连接对象的字符设置:

  • 从第3位开始,为每个组2的对象b分配专属的编码位置pos
  • 对于组1中需要和b连接的a,将a和b的pos位都设为'A'
  • 对于组1中不需要和b连接的a,将a的pos位设为'B'(确保和b的'A'或默认字符不同)
  • 组2对象b的非连接位置保持默认字符(比如'C'),这样无连接的a和b在所有位置都不会有相同字符,符合规则

3. 添加唯一标识位保证编码唯一性

利用M≥N+1的长度限制,给每个对象分配一个专属的特征位:

  • 组1的对象i,在第i+2位设为'B'(其他位置保持默认'C')
  • 组2的对象j(j=N+i),在第N+2+i位设为'A'(其他位置保持默认'C')
    这样每个对象的编码都会有一个独有的字符位置,确保所有编码唯一。

代码调整示例

#include <iostream>
#include <vector>
#include <unordered_set>
#include <unordered_map>

using namespace std;

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);

    int n, p, M;
    cin >> n >> p >> M;

    unordered_map<int, unordered_set<int>> b_to_as;
    for (int i = 0; i < p; ++i)
    {
        int a, b;
        cin >> a >> b;
        b_to_as[b].insert(a);
    }

    // 初始化编码为全'C'
    vector<string> codes(2 * n + 1, string(M, 'C'));

    // 组1内相连:第1位设为'A'
    for (int a = 1; a <= n; ++a)
    {
        codes[a][0] = 'A';
        codes[a][1] = 'C'; // 和组2第2位的'B'区分
    }

    // 组2内相连:第2位设为'B'
    for (int b = n+1; b <= 2*n; ++b)
    {
        codes[b][0] = 'C'; // 和组1第1位的'A'区分
        codes[b][1] = 'B';
    }

    // 处理跨组连接,从第3位开始分配位置
    int pos = 2;
    for (auto& [b, as] : b_to_as)
    {
        if (pos >= M) break; // 不超过M长度限制
        // 给需要连接的a和b设为'A'
        for (int a : as)
        {
            codes[a][pos] = 'A';
            codes[b][pos] = 'A';
        }
        // 不需要连接的a设为'B',确保和b的'A'/'C'不同
        for (int a = 1; a <= n; ++a)
        {
            if (!as.count(a))
            {
                codes[a][pos] = 'B';
            }
        }
        pos++;
    }

    // 添加唯一标识位,确保编码唯一
    // 组1的专属位:第3到第n+2位
    for (int a = 1; a <= n; ++a)
    {
        int unique_pos = a + 2;
        if (unique_pos >= M) break;
        codes[a][unique_pos] = 'B';
    }
    // 组2的专属位:第n+3到第2n+2位
    for (int i = 1; i <= n; ++i)
    {
        int b = n + i;
        int unique_pos = n + 2 + i;
        if (unique_pos >= M) break;
        codes[b][unique_pos] = 'A';
    }

    // 输出编码
    for (int i = 1; i <= 2*n; ++i)
    {
        cout << codes[i] << '\n';
    }

    return 0;
}

内容的提问来源于stack exchange,提问作者Szyszka947

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 16:04:56