• 简单环(状压dp)-----Java题解


     

    目录

    简单环 

    题目描述 

    输入描述:

    输出描述:

    输入

    输出

    备注:

     思路解析:

    代码实现


    题目来源:https://ac.nowcoder.com/acm/contest/25022/1022

    简单环 

    时间限制:C/C++ 2秒,其他语言4秒
    空间限制:C/C++ 262144K,其他语言524288K
    64bit IO Format: %lld

    题目描述 

    给定一张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

     思路解析:

    简单环的定义:

    (简单环:简单环又称简单回路,图的顶点序列中,除了第一个顶点和最后一个顶点相同外,其余顶点不重复出现的回路叫简单回路。或者说,若通路或回路不重复地包含相同的边,则它是简单的)

    因为他是一个n个点m条边的无向图,要求求简单环的数量,

    因为他没有重边,所以他从i节点到j节点的路径长度为一的路径只有一个,所以我们可以记录上一次状态的终点,然后从他转移到当前状态的终点上。dp[i][j]表示在状态i下,j为状态终点的路径方案数。

    dp[ s | (1 << (j - 1))][j] = (dp[ s | (1 << (j - 1))][j] + dp[ s | (1 << (j - 1))][i]) % mod;

    然后如果当前状态的终点可以走到起点的话他就构成了一个环。这里又因为一个环起点的位置并不影响这个环的结构,所以我们把一个状态中最小(最右)的节点作为起点,并且之后经过的起点一定要比起点大,这样可以避免重复计算。但他一定会重复计算两次这个无法避免

    如 中间状态 2 - 3 - 5,我们可以让起点连向2,也可以让起点连向5,所以统计完答案后,一定要除以2的逆元。

    代码实现

    1. import java.util.Scanner;
    2. import java.util.Vector;
    3. /**
    4. * @ProjectName: study3
    5. * @FileName: Ex22
    6. * @author:HWJ
    7. * @Data: 2023/11/8 20:38
    8. */
    9. public class Ex22 {
    10. static int mod = 998244353;
    11. public static void main(String[] args) {
    12. Scanner input = new Scanner(System.in);
    13. int n = input.nextInt();
    14. int m = input.nextInt();
    15. int k = input.nextInt();
    16. int[] ans = new int[k];
    17. int[][] dp = new int[1 << n][n + 1];
    18. int[][] map = new int[n + 1][n + 1];
    19. int[] num = new int[1 << n];
    20. for (int i = 0; i < 1 << n; i++) {
    21. num[i] = calc(i);
    22. }
    23. for (int i = 0; i < m; i++) {
    24. int a = input.nextInt();
    25. int b = input.nextInt();
    26. map[a][b] = 1;
    27. map[b][a] = 1;
    28. }
    29. for (int i = 1; i <= n; i++) {
    30. dp[1 << (i - 1)][i] = 1;
    31. }
    32. for (int s = 1; s < (1 << n); s++) {
    33. int st = -1;
    34. for (int i = 0; i < n; i++) {
    35. if ((s & (1 << i)) != 0){
    36. st = i + 1; // 在这个状态下 以这个节点作为状态。
    37. break;
    38. }
    39. }
    40. for (int i = st; i <= n; i++) {
    41. if ((s & (1 << (i - 1))) != 0){
    42. if (map[i][st] == 1 && num[s] > 2){
    43. // System.out.println(s + " " + num[s] % k);
    44. ans[num[s] % k] = (ans[num[s] % k] + dp[s][i]) % mod;
    45. }
    46. for (int j = st + 1; j <= n; j++) {
    47. if (map[i][j] == 1 && (s & (1 << (j - 1))) == 0){
    48. int a = s | (1 << (j - 1));
    49. dp[a][j] = (dp[a][j] + dp[s][i]) % mod;
    50. }
    51. }
    52. }
    53. }
    54. }
    55. for (int i = 0; i < k; i++) {
    56. System.out.println((ans[i] * quick(2)) % mod);
    57. }
    58. }
    59. public static int calc(int x){
    60. int ans = 0;
    61. while(x > 0){
    62. if ((x & 1) == 1) ans++;
    63. x >>= 1;
    64. }
    65. return ans;
    66. }
    67. public static long quick(long x){
    68. int a = mod - 2;
    69. long ans = 1;
    70. for (; a > 0; a >>= 1, x = x * x % mod) {
    71. if ((a & 1) == 1) ans = (ans * x) % mod;
    72. }
    73. return ans;
    74. }
    75. }

  • 相关阅读:
    软件工程
    Charles工具
    论坛回顾|用社区和开发者工具驱动软件供应链安全治理——章华鹏
    Android — 使用 Runtime 获取日志并保存至 download 目录
    Redis(五)的事务
    微信小程序 ssm图书馆付费自习室系统
    R语言提交后台任务Rstudio\nohup
    关于软件物料清单(SBOM),你所需要了解的一切
    .NET 6上的WebView2体验
    Mysql事务
  • 原文地址:https://blog.csdn.net/weixin_73936404/article/details/134299275