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] 304. Range Sum Query 2D - Immutable 二维区域和检索 - 不可变
Given a 2D matrix matrix, find the sum of the elements inside the rectangle defined by its upper lef ...
- [神经网络与深度学习][计算机视觉]SSD编译时遇到了json_parser_read.hpp:257:264: error: ‘type name’ declared as function ret
运行make之后出现如下错误: /usr/include/boost/property_tree/detail/json_parser_read.hpp:257:264: error: 'type n ...
- testNG的安装
1,testNG介绍 TestNG ( Testing Next Generation ,下一代测试技术) testNG的强大之处在于它是 利用注释(注解) 来强化测试功能的测试框架,可以用来做接口测 ...
- Netty原理架构解析
Netty原理架构解析 转载自:http://www.sohu.com/a/272879207_463994本文转载关于Netty的原理架构解析,方便之后巩固复习 Netty是一个异步事件驱动的网络应 ...
- 函数的学习1——定义函数&传递实参——参考Python编程从入门到实践
定义函数 def greet_user(): print("Hello") greet_user() # PEP8 函数和类的定义后空两行 1. 向函数传递参数 def greet ...
- 用Python递归做个多层次的文件执行
想用 递归实现多层次的 '.py'执行但是发现好像不能 import os def func(path): if os.path.isdir(path): for name in os.listdir ...
- LeetCode第151场周赛(Java)
这是我第一次写周赛的题目,而且还是虚拟的.从这次起,以后就将所有错过的题目都写到博客来.当然既然是我错的,那代码肯定不是我自己的.我会注明来源.并且我会自己敲一遍.多总结总是没坏处的. 另外比较糟糕的 ...
- 【LEETCODE】50、数组分类,简单级别,题目:888,1013,896,485,448,697
package y2019.Algorithm.array; import java.util.HashSet; import java.util.Set; /** * @ProjectName: c ...
- dubbo源码阅读之服务目录
服务目录 服务目录对应的接口是Directory,这个接口里主要的方法是 List<Invoker<T>> list(Invocation invocation) throws ...
- 【转载】C#中List集合使用RemoveRange方法移除指定索引开始的一段元素
在C#的List集合操作中,移除集合中的元素可以使用Remove方法和RemoveAt方法,这两个方法都是进行单个List集合元素的移除,其实List集合中还有个RemoveRange方法来移除一整段 ...