题目描述:

 A Simple Task
time limit per test

2 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

Given a simple graph, output the number of simple cycles in it. A simple cycle is a cycle with no repeated vertices or edges.

Input

The first line of input contains two integers n and m (1 ≤ n ≤ 19, 0 ≤ m) – respectively the number of vertices and edges of the graph. Each of the subsequent m lines contains two integers a and b, (1 ≤ a, b ≤ n, a ≠ b) indicating that vertices a and b are connected by an undirected edge. There is no more than one edge connecting any pair of vertices.

Output

Output the number of cycles in the given graph.

Examples
Input

Copy
4 6
1 2
1 3
1 4
2 3
2 4
3 4
Output

Copy
7
Note

The example graph is a clique and contains four cycles of length 3 and three cycles of length 4.

思路:

题目要求是给一个图,判断这个图里有几个环,一个环内,每两个顶点间只能由一条边相连。

刚开始:深度优先搜索,对每个顶点做一次深搜,第二次遇到刚开始的顶点,环ans++;最后由于重复的环ans/=2,得出答案。然而,这样是会超时的。

原因呢,是大量的重复计算,如下图的解答树:1-3-2-4-1和1-4-2-3-1实际上是一样的环,同一个顶点的环有重复,不同顶点为起点的环也可能重复

然后,dp是不可能dp的,这辈子都不会dp,只能勉强用暴搜来维持生活这样子,

考虑状态压缩dp,用dp[s][u]来表示,现在的点的访问状态用s的二进制形式储存着,dp[s][u],表示在这个访问状态下,到达点u的方式有多少种,其中s二进制的最右端不为零的位置对应的是路径的起点,(如100100,起点为3)怎么算起点呢?记得上篇博客介绍过__builtin_ctz来计算二进制末尾0的个数start=__builtin_ctz(s)+1就是起点的位置。

考虑初始条件,d[1<<(i-1)][i]=1(表示只有自己点访问的情况下,自己到自己点的方式只有一种)。

接着是状态转移,状态转移可写作dp[s][u] = sum(dp[s][i]|G[i][u]==1),方向是从i到u,

也可以写成是方向u到i,dp[s'][i]+=dp[s][u](G[u][i]==1&&i!=start&&1<<(i-1)&s==0)(s'=1<<(i-1)|s),即当i与u有边,而且i不是起点,而且状态s中的i个位置上i没有出现过,那么更新s‘i的数值。

终点呢,是如果状态转移的时候,发现从u到i结果i就是起点,而且状态s对应的i位上已经出现过一次i,说明已经形成了一个环。这是ans+=dp[s][u]。

为了方便理解,举一个栗子

现在有图:GFEDCBA,其中只有ACEF形成一个环

G:GFEDCBA

s’:0 1 1 0 1 0 1(s的二进制表示),假设现在状态就是这个s’,我已经从1(起点)开始,初始状态为s(不是s'),不断进行状态转移得到了这个未来会遍历到的状态(s'),

等到我终于遍历到这个s'的时候,我遍历图,遇到F点,发现他和A点有边相连,而且A 是顶点,而且A点已经访问过,那么!一个环到了!

注意的是这个算法会把两个直接有边相连的顶点看成一个环,(想想为什么),比如CA相连,101在以1为起点u为3是发现3有连1的边,而且出现过,而且是起点,就以为是一个环了。所以最后有几个边直接相连就多了几个环,减去就是,还有一点,换会重复两遍,一个方向一遍,要减掉

注意:由于n的数字很小,用比较tricky的思维来看,应该找不到一个多项式算法,因此我们可以设计一个阶层或指数级的算法。有兴趣的同学可以证明该问题是个NP问题。
一个环是由若干个节点以及节点的顺序决定的。若用最暴力的方法统计n个节点的无向图中环的个数,则根据圆排列公式需要枚举O(∑ni=3(i!2i))
个环,每个环用O(n)的时间复杂度检查每个环是否真的存在,因此,总的时间复杂度则为O(n!)。由于该问题的n最大值是19,而19!是一个庞大的数字,所以阶层复杂度的算法是不能够被接受的。

所以数据要开long long

代码:

 #include <iostream>
#define max_n 20
using namespace std;
int n;
int m;
int G[max_n][max_n];
long long dp[<<max_n][max_n];
long long ans = ;
int st(int n)
{
return __builtin_ctz(n)+;
}
int main()
{
//cout << __builtin_ctz(4)+1 << endl;
cin >> n >> m;
for(int i = ;i<m;i++)
{
int f,t;
cin >> f >> t;
G[f][t] = G[t][f] = ;
}
for(int i = ;i<=n;i++)
{
dp[<<(i-)][i] = ;
}
long long S = (<<n)-;
//cout << S << endl;
for(int s = ;s<=S;s++)
{
for(int u = ;u<=n;u++)
{
if(dp[s][u]==) //没有方法可以按着s到u
{
continue;
}
int start = st(s);
//cout << start << endl;
for(int i = start;i<=n;i++)
{
if(G[i][u])
{
if((s&(<<(i-)))&&i==start)
{
ans += dp[s][u];
}
else if(!(s&(<<(i-))))
{
long long ss = s|(<<(i-));
dp[ss][i] += dp[s][u];
}
}
}
}
}
ans -= m;
ans /= ;
cout << ans << endl;
return ;
}

以上还不明白?正常,我可能也没讲太清楚,推荐给你:

餃子,Codeforces A Simple Task 统计简单无向图中环的个数,https://blog.csdn.net/fangzhenpeng/article/details/49078233

还有:C20191904,CodeForces -  A Simple Task,https://blog.csdn.net/C20191904/article/details/81513904

Codeforces C. A Simple Task(状态压缩dp)的更多相关文章

  1. [CodeForces 11D] A Simple Task - 状态压缩入门

    状态压缩/Bitmask 在动态规划问题中,我们会遇到需要记录一个节点是否被占用/是否到达过的情况.而对于一个节点数有多个甚至十几个的问题,开一个巨型的[0/1]数组显然不现实.于是就引入了状态压缩, ...

  2. Codeforces 580D Kefa and Dishes(状态压缩DP)

    题目链接:http://codeforces.com/problemset/problem/580/D 题目大意:有n盘菜每个菜都有一个满意度,k个规则,每个规则由x y c组成,表示如果再y之前吃x ...

  3. Codeforces 4538 (状态压缩dp)Little Pony and Harmony Chest

    Little Pony and Harmony Chest 经典状态压缩dp #include <cstdio> #include <cstring> #include < ...

  4. FZU-2218 Simple String Problem(状态压缩DP)

      原题地址: 题意: 给你一个串和两个整数n和k,n表示串的长度,k表示串只有前k个小写字母,问你两个不含相同元素的连续子串的长度的最大乘积. 思路: 状态压缩DP最多16位,第i位的状态表示第i位 ...

  5. HOJ 2226&POJ2688 Cleaning Robot(BFS+TSP(状态压缩DP))

    Cleaning Robot Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 4264 Accepted: 1713 Descri ...

  6. HDU_3182_Hamburger Magi_状态压缩dp

    Hamburger Magi Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  7. hoj2662 状态压缩dp

    Pieces Assignment My Tags   (Edit)   Source : zhouguyue   Time limit : 1 sec   Memory limit : 64 M S ...

  8. POJ 3254 Corn Fields(状态压缩DP)

    Corn Fields Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 4739   Accepted: 2506 Descr ...

  9. [知识点]状态压缩DP

    // 此博文为迁移而来,写于2015年7月15日,不代表本人现在的观点与看法.原始地址:http://blog.sina.com.cn/s/blog_6022c4720102w6jf.html 1.前 ...

随机推荐

  1. [LeetCode] 257. Binary Tree Paths 二叉树路径

    Given a binary tree, return all root-to-leaf paths. For example, given the following binary tree: 1 ...

  2. socket支持ipv6

    转自:https://www.jianshu.com/p/9926b99a7fef 以前cocos2d-x的项目里都使用的是libwebsocket,如果想支持ipv6,只需要升级相应的库即可,现在有 ...

  3. springboot打war包部署到tomcat

    1:build.gradle plugins { id 'org.springframework.boot' version '2.1.5.RELEASE' id 'java' } apply plu ...

  4. Postgresql集群解决方案测试报告

    1 测试主体 本次测试的主体有3个,分别为: GreenPlum集群,下文简称为GP Postgres-XC集群,下文简称为XC Postgresql单数据库实例,下文简称为pgsql GP和XC都选 ...

  5. python学习-70 自定制format

    # 自定义format dic_date = { 'ymd':'{0.year}:{0.month}:{0.day}', 'dmy':'{0.day}-{0.month}-{0.year}' } cl ...

  6. pychram 中 Terminal 中 git log 中文乱码解决办法

    添加环境变量 set LESSCHARSET=utf-8 执行以下命令 git config --global core.quotepath false 不成功执行以下命令 git config -- ...

  7. 初学者用pycharm创建一个django项目和一个app时需要注意的事项

    如何新建一个djiango项目: 1.在pycharm中点击File,选择new project,点击djiango,在右面的Location中将untitile改为你的项目名,其余部分注意见下图: ...

  8. 高仿linux下的ls -l命令——C语言实现

    主要用到的函数可以参考头文件,仅仅支持ls -l这功能,扩展就交给大家了0.0 相关测试图片: ​ ​ 话不多说,直接上码 #include <stdio.h> #include < ...

  9. 有关java中的try{}catch(){}的讲解

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/qq_38225558/article/d ...

  10. AX 2009中Set运用

    Set运行: 例子: Set m_set = new Set(Types::String); m_set.add("AAA"); m_set.add("BBB" ...