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] 337. House Robber III 打家劫舍 III
The thief has found himself a new place for his thievery again. There is only one entrance to this a ...
- Kubernetes 控制器之 Service 讲解(七)
一.背景介绍 我们这里准备三台机器,一台master,两台node,采用kubeadm的方式进行安装的,安装过程大家可以参照我之前的博文. IP 角色 版本 192.168.1.200 master ...
- 修改jar的.class文件,并重新打包
使用javassist修改.class文件,并重新打包 Javassist是一款字节码编辑工具,可以直接编辑和生成Java生成的字节码,以达到对.class文件进行动态修改的效果.熟练使用这套工具,可 ...
- 【视频开发】GPU编解码:GPU硬解码---DXVA
GPU编解码:GPU硬解码---DXVA 一.DXVA介绍 DXVA是微软公司专门定制的视频加速规范,是一种接口规范.DXVA规范制定硬件加速解码可分四级:VLD,控制BitStream;IDCT,反 ...
- iOS @功能的部分实现思路
需求描述 1. 发布信息时,通过键盘键入@符号,或者点选相关功能键,唤醒@列表,进行选择 2.选择结束后,输入栏改色显示相关内容 3.删除时,整体删除@区块,且不能让光标落在@区块之间 实现步骤 1. ...
- Qt5 QtQuick系列----QtQuick的Secne Graph剖析(1)
教是言词, 实不是道,道本无言, 言说是妄.------- 达摩 Qt 5提出了一个新的渲染底层,以替代Qt4时期的Graphics View,这个渲染底层就是Scene Graph.Scene Gr ...
- ubuntu12下安装unixODBC(mysql)
转自:https://blog.51cto.com/dreamylights/1321678 1. 需要的包 unixODBC源码包unixODBC-2.2.14.tar.gz mysql 驱动 my ...
- ply2obj
""" Simple script to convert ply to obj models """ import os from argp ...
- Ant Design Vue select下拉列表设置默认值
在项目中需要为Ant Design Vue 的 select 组件设置一个默认值,如下图所示的状态下拉选择框,默认选择全部 代码如下: <a-select v-model="query ...
- Java线程设计模式(五)
多线程的设计模式:Future模式.Master-Worker模式,生产消费者模式 public interface Data { String getRequest(); } public clas ...