Codeforces C. A Simple Task(状态压缩dp)
题目描述:
2 seconds
256 megabytes
standard input
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.
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 the number of cycles in the given graph.
4 6
1 2
1 3
1 4
2 3
2 4
3 4
7
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)的更多相关文章
- [CodeForces 11D] A Simple Task - 状态压缩入门
状态压缩/Bitmask 在动态规划问题中,我们会遇到需要记录一个节点是否被占用/是否到达过的情况.而对于一个节点数有多个甚至十几个的问题,开一个巨型的[0/1]数组显然不现实.于是就引入了状态压缩, ...
- Codeforces 580D Kefa and Dishes(状态压缩DP)
题目链接:http://codeforces.com/problemset/problem/580/D 题目大意:有n盘菜每个菜都有一个满意度,k个规则,每个规则由x y c组成,表示如果再y之前吃x ...
- Codeforces 4538 (状态压缩dp)Little Pony and Harmony Chest
Little Pony and Harmony Chest 经典状态压缩dp #include <cstdio> #include <cstring> #include < ...
- FZU-2218 Simple String Problem(状态压缩DP)
原题地址: 题意: 给你一个串和两个整数n和k,n表示串的长度,k表示串只有前k个小写字母,问你两个不含相同元素的连续子串的长度的最大乘积. 思路: 状态压缩DP最多16位,第i位的状态表示第i位 ...
- HOJ 2226&POJ2688 Cleaning Robot(BFS+TSP(状态压缩DP))
Cleaning Robot Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 4264 Accepted: 1713 Descri ...
- HDU_3182_Hamburger Magi_状态压缩dp
Hamburger Magi Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)To ...
- hoj2662 状态压缩dp
Pieces Assignment My Tags (Edit) Source : zhouguyue Time limit : 1 sec Memory limit : 64 M S ...
- POJ 3254 Corn Fields(状态压缩DP)
Corn Fields Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 4739 Accepted: 2506 Descr ...
- [知识点]状态压缩DP
// 此博文为迁移而来,写于2015年7月15日,不代表本人现在的观点与看法.原始地址:http://blog.sina.com.cn/s/blog_6022c4720102w6jf.html 1.前 ...
随机推荐
- [LeetCode] 268. Missing Number 缺失的数字
Given an array containing n distinct numbers taken from 0, 1, 2, ..., n, find the one that is missin ...
- NB-IOT技术学习问题记录
1. TAU是什么,跟踪区更新 2. 小区和基站的区别 3. 附着和设备注册的关系? 4. 不携带PDN是什么意思? 5. PLMN 公共陆地移动网络,和小区的关系,区别?
- java的字节码bytecode
字节码名字的由来 字节码以一个字节即8bit为最小单位储存:字节码是java程序编译后的结果:字节码是一组8位字节为基础单位的二进制流 Java从源文件到执行的过程. 如何阅读JAVA字节码
- 面试之leetcode链表
1 数组 (1)数组的插入 如果是插入到最后,那么不用移动O(1),如果插入位置在中间为O(n).所以最好O(1),最坏O(N),平均O(N),为了插入能达到O(1),插入O(1).引入了链表 2 链 ...
- spring cloud集成canal
前提 win运行canal 加入canal依赖 <dependency> <groupId>com.alibaba.otter</groupId> <arti ...
- Connection: close和Connection: keep-alive有什么区别
转自:https://www.cnblogs.com/TinyMing/p/4597136.html 看到有人问Connection: close和Connection: keep-alive有什么区 ...
- quartz2.3.0系列目录——带您由浅入深全面掌握quartz2.3.0
quartz2.3.0系列目录 官网下载地址:http://www.quartz-scheduler.org/downloads/ 本系列demo全部来源于官网,仅仅是简化和汉化了注释!一部分代码de ...
- Spark 系列(二)—— Spark开发环境搭建
一.安装Spark 1.1 下载并解压 官方下载地址:http://spark.apache.org/downloads.html ,选择 Spark 版本和对应的 Hadoop 版本后再下载: 解压 ...
- vs、eclips、Idea调试技巧
vs F5:进入下一个断点 F10:不进入子函数 F11:进入子函数 Ctrl + M + O: 折叠所有方法 Ctrl + M + M: 折叠或者展开当前方法 Ctrl + M + L: 展开所有方 ...
- 【转载】C#中使用List集合的Insert方法在指定位置插入数据
在C#的List集合等数据类型变量中,我们可以使用List集合的Insert方法在指定的索引位置插入一个新数据,例如指定在List集合的第一个位置写入一个新数据或者在List集合的中间某个位置插入个新 ...