NC16544 简单环
题目
题目描述
给定一张n个点m条边的无向图,求出图中所有简单环的数量。(简单环:简单环又称简单回路,图的顶点序列中,除了第一个顶点和最后一个顶点相同外,其余顶点不重复出现的回路叫简单回路。或者说,若通路或回路不重复地包含相同的边,则它是简单的)
输入描述
第一行三个数n m k (k在输出描述中提到)
接下来m行每行两个数u,v表示u到v之间存在一条边(无重边)
输出描述
输出k行每行1个整数
第i个数表示长度%k==i-1的简单环的数量(对998244353取模)
(只记录长度大于2的简单环的数量)
示例1
输入
4 6 3 1 2 2 3 3 4 4 1 2 4 1 3
输出
4 3 0
备注
n<=20
m<=n*(n-1)/2
k<=n
题解
知识点:状压dp。
比普通的TSP多了个环计数,应当在遍历每个状态时,查看起点和终点是否能够连接,能的话就给这个长度计数。为了避免重复计算,每次第一个 作为起点,选择终点应当在起点之后,防止出现不同的终点和起点对应同一个环的重复。最后应该除以二,消除顺时针逆时针的重复。
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> using namespace std; const int mod = 998244353; int g[27][27]; int dp[(1 << 20) + 7][27];///状态i且最后一个点为j时,除去连成环会重复的可能的所有方案 int ans[27]; int main() { std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int n, m, q; cin >> n >> m >> q; for (int i = 1;i <= m;i++) { int u, v; cin >> u >> v; g[u][v] = 1; g[v][u] = 1; } for (int i = 1;i <= n;i++) dp[1 << i - 1][i] = 1; for (int i = 1;i < (1 << n);i++) { int s = 0;///规定每个状态的第一个1为起点 for (int j = 1;j <= n;j++) { if (i & (1 << j - 1)) { s = j; break; } } int len = __builtin_popcount(i); for (int j = s + 1;j <= n;j++) {///枚举状态i的最后一个点 ///最后一个点要在起点后面,因为最终会连成环,防止环形性重复计数,如..j...s.. <-> ..s...j..的等价情况 if (!(i & (1 << j - 1))) continue; for (int k = s;k <= n;k++) {///枚举上一次的最后一个点,只会在起点及其后面 if (!(i & (1 << k - 1))) continue; if (g[j][k]) dp[i][j] = (dp[i][j] + dp[i ^ (1 << j - 1)][k]) % mod;///如果有通路,则可以连上 }///计算合法链的方案 if (g[s][j] && len >= 3)///起点和终点能连上且长度大于等于3时,属于能连成合法的环 ans[len % q] = (ans[len % q] + dp[i][j]) % mod; } } for (int i = 0;i < q;i++) cout << 1LL * ans[i] * 499122177 % mod << '\n';///顺时针逆时针的重复计数消除 return 0; }
本文来自博客园,作者:空白菌,转载请注明原文链接:https://www.cnblogs.com/BlankYang/p/16653924.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧