[蓝桥杯]模型染色

news2025/6/6 23:49:04

模型染色

题目描述

在电影《超能陆战队》中,小宏可以使用他的微型机器人组合成各种各样的形状。

现在他用他的微型机器人拼成了一个大玩具给小朋友们玩。为了更加美观,他决定给玩具染色。

小宏的玩具由 nn 个球型的端点和 mm 段连接这些端点之间的边组成。下图给出了一个由 5 个球型端点和 4 条边组成的玩具,看上去很像一个分子的球棍模型。

由于小宏的微型机器人很灵活,这些球型端点可以在空间中任意移动,同时连接相邻两个球型端点的边可以任意的伸缩,这样一个玩具可以变换出不同的形状。在变换的过程中,边不会增加,也不会减少。

小宏想给他的玩具染上不超过 kk 种颜色,这样玩具看上去会不一样。如果通过变换可以使得玩具变成完全相同的颜色模式,则认为是本质相同的染色。现在小宏想知道,可能有多少种本质不同的染色。

输入描述

输入的第一行包含三个整数 n,m,kn,m,k,分别表示小宏的玩具上的端点数、边数和小宏可能使用的颜色数。端点从 1 到 nn编号。

接下来 mm 行每行两个整数 a,ba,b,表示第 aa 个端点和第 bb 个端点之间有一条边。输入保证不会出现两条相同的边。

其中,1≤n≤10,1≤m≤45,1≤k≤301≤n≤10,1≤m≤45,1≤k≤30。

输出描述

输出一行,表示本质不同的染色的方案数。由于方案数可能很多,请输入方案数除 10007 的余数。

输入输出样例

示例

输入

3 2 2
1 2
3 2

输出

6

样例说明

令 (a,b,c)(a,b,c) 表示第一个端点染成 aa,第二个端点染成 bb,第三个端点染成 cc,则下面 6 种本质不同的染色:(1,1, 1), (1, 1, 2), (1, 2, 1), (1, 2, 2), (2, 1, 2), (2, 2, 2)。

而(2, 1, 1)与(1, 1, 2)是本质相同的,(2, 2, 1)与(1, 2, 2)是本质相同的。

运行限制

  • 最大运行时间:5s
  • 最大运行内存: 512M

总通过次数: 118  |  总提交次数: 184  |  通过率: 64.1%

难度: 困难   标签: 2015, 国赛, 搜索

算法思路:基于Burnside引理的图染色计数

本问题要求计算在图的连续变形(自同构)下本质不同的染色方案数。核心思路是使用Burnside引理:本质不同的染色方案数等于自同构群作用下所有置换的不动点数的平均值。具体步骤如下:

  1. ​问题转化​​:将本质不同的染色方案转化为在图的顶点自同构群作用下的轨道数。
  2. ​Burnside引理​​:本质不同的染色方案数公式为:
    ans=∣G∣1​∑g∈G​kc(g)mod10007
    其中 ∣G∣ 是自同构群大小,c(g) 是置换 g 的轮换个数,k 是颜色数。
  3. ​自同构判定​​:置换 g 是自同构当且仅当对原图的每条边 (u,v),置换后 (g(u),g(v)) 仍是图中的边。
  4. ​轮换分解​​:对每个自同构置换,分解轮换并统计轮换个数 c(g)。

算法步骤

  1. ​输入处理​​:读取顶点数 n、边数 m、颜色数 k,构建邻接矩阵。
  2. ​置换生成​​:枚举 0 到 n−1 的所有排列(使用 next_permutation)。
  3. ​自同构检查​​:对每个置换,检查原图所有边置换后是否仍是图中的边。
  4. ​轮换分解​​:对自同构置换进行轮换分解,统计轮换个数 c(g)。
  5. ​不动点计算​​:计算 kc(g)mod10007 并累加。
  6. ​结果计算​​:累加和乘以自同构群大小的逆元(模 10007)。

代码实现(C++)

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

const int MOD = 10007;

// 快速幂取模
int mod_pow(int base, int exp, int mod) {
    int res = 1;
    base %= mod;
    while (exp) {
        if (exp & 1) res = (res * base) % mod;
        base = (base * base) % mod;
        exp >>= 1;
    }
    return res;
}

int main() {
    int n, m, k;
    cin >> n >> m >> k;
    
    // 邻接矩阵和边列表初始化
    vector<vector<int>> adj(n, vector<int>(n, 0));
    vector<pair<int, int>> edges;
    
    // 输入边并构建邻接矩阵
    for (int i = 0; i < m; i++) {
        int a, b;
        cin >> a >> b;
        a--; b--; // 转换为0-index
        adj[a][b] = adj[b][a] = 1;
        if (a > b) swap(a, b);
        edges.push_back({a, b});
    }
    
    // 生成初始置换 [0, 1, ..., n-1]
    vector<int> perm(n);
    for (int i = 0; i < n; i++) perm[i] = i;
    
    int group_size = 0;    // 自同构群大小
    int sum_terms = 0;     // 累加项
    
    do {
        bool is_automorphism = true;
        // 检查每条边置换后是否仍存在
        for (auto &e : edges) {
            int u = e.first, v = e.second;
            if (!adj[perm[u]][perm[v]]) {
                is_automorphism = false;
                break;
            }
        }
        
        if (is_automorphism) {
            group_size++;
            // 轮换分解
            vector<bool> visited(n, false);
            int cycle_count = 0;
            for (int i = 0; i < n; i++) {
                if (!visited[i]) {
                    cycle_count++;
                    int cur = i;
                    while (!visited[cur]) {
                        visited[cur] = true;
                        cur = perm[cur];
                    }
                }
            }
            // 累加 k^{cycle_count} mod MOD
            sum_terms = (sum_terms + mod_pow(k, cycle_count, MOD)) % MOD;
        }
    } while (next_permutation(perm.begin(), perm.end()));
    
    // 计算逆元:inv = group_size^{MOD-2} mod MOD
    int inv = mod_pow(group_size, MOD-2, MOD);
    int ans = sum_terms * inv % MOD;
    cout << ans << endl;
    
    return 0;
}

代码解析

  1. ​输入处理​​(L19-27):
    • 读取 n,m,k,初始化邻接矩阵 adj 和边列表 edges
    • 将输入的边转换为0-index存储,并标记邻接矩阵。
  2. ​置换生成​​(L30-33):
    • 初始化置换数组 perm 为 [0,1,…,n−1]。
    • 使用 next_permutation 遍历所有排列。
  3. ​自同构检查​​(L36-44):
    • 对每条边 (u,v),检查置换后 (perm[u],perm[v]) 是否仍是图中的边。
    • 若所有边检查通过,则判定为自同构。
  4. ​轮换分解​​(L47-58):
    • 使用 visited 数组标记访问过的顶点。
    • 对每个未访问顶点进行DFS遍历,统计轮换个数 cycle_count
  5. ​不动点累加​​(L60):
    • 计算 k^{\text{cycle_count}} \mod 10007 并累加到 sum_terms
  6. ​结果计算​​(L64-66):
    • 计算自同构群大小的逆元 inv(费马小定理)。
    • 输出 sum_terms×invmod10007。

实例验证

​输入​​:3 2 2,边 (1,2) 和 (3,2)


​自同构群​​:

  • 单位置换:[0,1,2] → 轮换数=3 → 23=8
  • 置换 [2,1,0]:轮换数=2 → 22=4
  • 总和 8+4=12,群大小 2 → 12/2=6 ✓

注意事项

  1. ​顶点索引转换​​:输入顶点从1开始,需转换为0-index处理。
  2. ​逆元计算​​:模数 10007 是素数,使用费马小定理求逆元。
  3. ​性能边界​​:n=10 时置换数 10!≈3.6×106,边数 m≤45,总操作数约 1.6×108,在5秒内可完成。
  4. ​轮换分解​​:使用DFS避免重复计数。

多方位测试点

​测试类型​​输入样例​​预期输出​​验证要点​
最小图(n=1)1 0 33单点边界
无自同构图3 1 2
1 2
4单位置换唯一性
完全图(K4​)4 6 315对称性处理
星形图4 3 2
1 2 1 3 1 4
6叶子交换对称性
全边图(m=45)10 45 51完全图自同构群大小 10!

优化建议

  1. ​剪枝优化​​:
    // 在生成排列时提前终止无效置换
    if (!is_automorphism) continue;
  2. ​并行计算​​(OpenMP):
    #pragma omp parallel for reduction(+:sum_terms, group_size)
    for (int i = 0; i < total_perm; i++) {
        // 并行处理置换
    }
  3. ​自同构群加速​​:
    • 使用nauty等图同构库直接生成自同构群,避免全排列枚举。
  4. ​缓存优化​​:
    • 预计算幂结果:kc 中 c≤n,可预先计算 k1 到 kn 的模值。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2400913.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

卡西欧模拟器:Windows端功能强大的计算器

引言 大家还记得初中高中时期用的计算器吗&#xff1f;今天给大家分享的就是一款windows端的卡西欧计算器。 软件介绍 大家好&#xff0c;我是逍遥小欢。 CASIO fx-9860G是一款功能强大的图形计算器&#xff0c;适用于数学、科学和工程计算。以下是其主要功能和特点的详细介…

机器学习基础(三) 逻辑回归

目录 逻辑回归的概念核心思想 Sigmoid 函数 逻辑回归的原理和底层优化手段伯努利分布最大似然估计 Maximum Likelihood Estimation &#xff08;MLE&#xff09;伯努利分布的似然函数交叉熵损失函数&#xff08;Cross-Entropy Loss&#xff09;&#xff0c;也称为 对数损失&…

Qwen-3 微调实战:用 Python 和 Unsloth 打造专属 AI 模型

虽然大家都忙着在 DeepSeek 上构建应用&#xff0c;但那些聪明的开发者们却悄悄发现了 Qwen-3 的微调功能&#xff0c;这可是一个隐藏的宝藏&#xff0c;能把通用型 AI 变成你的专属数字专家。 通过这篇文章&#xff0c;你将学到如何针对特定用途微调最新的 Qwen-3 模型。无论…

微软Build 2025:Copilot Studio升级,解锁多智能体协作未来

微软Build 2025大会圆满落幕&#xff0c;作为年度科技盛会&#xff0c;它一直是开发与AI技术突破性创新的重要展示平台。对于工程师、创作者和领域专家来说&#xff0c;这是了解微软生态未来动向的关键时刻。今年&#xff0c;Microsoft Copilot Studio推出了一系列新功能&#…

设计模式——系统数据建模设计

摘要 本文主要介绍了UML在软件系统分析和设计中的应用&#xff0c;详细阐述了六大类关系&#xff08;泛化、实现、依赖、关联、聚合、组合&#xff09;及其在UML类图中的表示方法&#xff0c;并通过具体例子说明了这些关系在实际编程中的应用。同时&#xff0c;文章还概述了UM…

解决docker运行zentao 报错:ln: failed to create symbolic link ‘/opt/zbox/tmp/mysq

1 背景描述 禅道使用docker部署运行过一段&#xff0c;服务正常。 后因服务器断电重启&#xff0c;禅道服务也随docker一起启动&#xff0c;但是服务却无法访问。如下如&#xff1a; 2 查看日志&#xff0c;定位原因 查看禅道日志&#xff1a; # docker logs zentao容器di…

OA工程自动化办公系统 – 免费Java源码

概述 功能完备的OA工程自动化办公系统Java源码&#xff0c;采用主流技术栈开发&#xff0c;无论是学习SpringBoot框架还是开发企业级应用&#xff0c;都是不可多得的优质资源。 主要内容 技术架构 ​​后端技术栈​​&#xff1a; 核心框架&#xff1a;SpringBoot 2.xORM框…

Apache IoTDB V2.0.3 发布|新增元数据导入导出脚本适配表模型功能

Release Announcement Version 2.0.3 Apache IoTDB V2.0.3 已经发布&#xff01; V2.0.3 作为树表双模型正式版本&#xff0c;主要新增元数据导入导出脚本适配表模型、Spark 生态集成&#xff08;表模型&#xff09;、AINode 返回结果新增时间戳&#xff0c;表模型新增部分聚…

某校体育场馆结构自动化监测

1. 项目简介 某小学学校成立于2020年&#xff0c;是一所公办小学&#xff0c;以高起点定位为该区优质教育新增长极&#xff0c;依托当地学院及教师进修学院附属小学资源&#xff0c;注重学生综合素质培养&#xff0c;近年来&#xff0c;该小学聚焦“五育” 领域&#xff0c;不…

Android 3D球形水平圆形旋转,旋转动态更换图片

看效果图 1、事件监听类 OnItemClickListener&#xff1a;3D旋转视图项点击监听器接口 public interface OnItemClickListener {/*** 当旋转视图中的项被点击时调用** param view 被点击的视图对象* param position 被点击项在旋转视图中的位置索引&#xff08;从0开始&a…

数据结构与算法学习笔记(Acwing 提高课)----动态规划·树形DP

数据结构与算法学习笔记----动态规划树形DP author: 明月清了个风 first publish time: 2025.6.4 ps⭐️树形动态规划&#xff08;树形DP&#xff09;是处理树结构问题的一种动态规划方法&#xff0c;特征也很明显&#xff0c;会有一个树形结构&#xff0c;其实是DFS的优化。…

leetcode hot100刷题日记——36.最长连续序列

解答&#xff1a; 实际上在哈希表中存储不重复的数字。 然后遍历哈希表&#xff0c;找间隔&#xff0c;更新最大间隔。 class Solution { public:int longestConsecutive(vector<int>& nums) {unordered_set<int>hash;for(int num:nums){hash.insert(num);}in…

CentOS7关闭防火墙、Linux开启关闭防火墙

文章目录 一、firewalld开启、关闭防火墙1、查看防火墙状态 一、firewalld开启、关闭防火墙 以下命令在linux系统CentOS7中操作开启关闭防火墙 # 查询防火墙状态 systemctl status firewalld.service # 开启防火墙 systemctl start firewalld.service # 开机自启动防火墙 syste…

PyTorch——搭建小实战和Sequential的使用(7)

import torch from torch import nn from torch.nn import Conv2d, MaxPool2d, Flatten, Linearclass TY(nn.Module):def __init__(self):"""初始化TY卷积神经网络模型模型结构&#xff1a;3层卷积池化&#xff0c;2层全连接设计目标&#xff1a;处理32x32像素的…

Python 开发效率秘籍:PyCharm、VS Code 与 Anaconda 配置与实战全解

目录 一、IDE(集成开发环境)是什么?二、Python IDE有哪些&#xff0c;哪款适合初学者&#xff1f;三、Visual Studio Code下载和安装教程3.1 VS Code下载和安装3.2 VS Code运行Python程序 四、PyCharm下载和安装教程4.1 PyCharm下载4.2 PyCharm安装4.3 运行PyCharm4.4 创建工程…

大话软工笔记—组合要素1之要素

1. 要素来源 对象是要素的来源&#xff0c;要素是从对象分解而来的。可将对象分为优化类和非优化类&#xff0c;如下图所示。 对象分类图 2. 要素的概念 2.1 要素的定义 要素&#xff0c;是构成事物必不可少的因素&#xff0c;要素的集合体构成了对象。 2.2 要素的内容 要…

平台化 LIMS 系统架构 跨行业协同与资源共享的实现路径

在科技快速发展的今天&#xff0c;质检行业正面临着效率、合规和数据安全的多重挑战。新一代质检 LIMS 系统以智能化与平台化为核心&#xff0c;为实验室管理提供了全新的解决方案。 一、智能化&#xff1a;从数据采集到分析的全流程升级 传统质检流程中&#xff0c;人工数据录…

RedisTemplate查询不到redis中的数据问题(序列化)

RedisTemplate查询不到redis中的数据问题(序列化) 一.问题描述 存入Redis中的值取出来却为null,问题根本原因就是RedisTemplate和StringRedisTemplate的序列化问题、代码示例&#xff1a; SpringBootTest class Redis02SpringbootApplicationTests {Autowiredprivate RedisTe…

SkyWalking如何实现跨线程Trace传递

一、概述 SkyWalking 的中构建 Trace 信息时会借助 ThreadLocal来存储一些上下文信息&#xff0c;当遇到跨线程的时候&#xff0c;如果 Trace 的上下文信息没有传递到新线程的ThreadLocal 中&#xff0c;那么链路就断开了。那么SkyWalking是如何解决这个问题的呢&#xff1f; …

使用 Spring Boot 3.3 和 JdbcTemplate 操作 MySQL 数据库

在现代的 Java 应用开发中&#xff0c;Spring Boot 提供了强大的工具来简化数据库操作。JdbcTemplate 是 Spring 提供的一个核心类&#xff0c;用于简化 JDBC 操作&#xff0c;减少样板代码。本文将介绍如何在 Spring Boot 3.3 项目中使用 JdbcTemplate 来操作 MySQL 数据库&am…