[CodeForces 11D] A Simple Task - 状态压缩入门
状态压缩/Bitmask
在动态规划问题中,我们会遇到需要记录一个节点是否被占用/是否到达过的情况。而对于一个节点数有多个甚至十几个的问题,开一个巨型的[0/1]数组显然不现实。于是就引入了状态压缩,用一个整数的不同二进制位来表示该节点的状态。
Description
- 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&Output
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.
Sample
Input
4 6
1 2
1 3
1 4
2 3
2 4
3 4
Output
7
Solution
- 大意是求简单无向图的环数,暴搜遍历必然会TLE,重复环的处理也十分复杂。
- 考虑状态压缩,用二进制位来表示当前状态是否经过了特定的点。为了减轻重复环的处理难度,我们约定只计算起点序小于当前节点的状态(在代码中会有解释)。若节点i与当前节点y之间有边,状态的转移有以下几种条件:
- 若当前状态的起点序大于当前节点 (k&-k>(1<<y)) ,不转移。
- 若当前状态经过了当前节点 (k&(1<<y)) ,判断起点是否就是当前节点,若是,意味着我们找到了环,更新答案。
- 若当前状态没有经过当前节点,则更新经过当前节点的状态 f[k|(1<<y)][y] ,由 f[k][i] 贡献。
- 遍历以每个节点为起点的所有状态,我们可以得到一个ans。但需要注意的是,这种计算方式会将两点间连一条边的路径(为什么?)和一个环的双向都计算在内,输出时需要将答案减去边数再除以2.
细节与边界处理 - 由于二进制位需要从第0位开始,我们不妨在建图时同一将点的编号减1,方便计算。节点的遍历也要从0到n-1。
- 初始状态下,以节点i为起点,只经过i的状态,f值为1。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxn 20 #define maxe 400 using namespace std; typedef long long ll; struct edge{ int to,nxt; }e[maxe]; int n,m,x,y,edgenum,lnk[maxn]; ll ans,f[1<<maxn][maxn]; void add(int bgn,int end)//事实上,节点比较少,邻接矩阵也可以存下 { edgenum++; e[edgenum].to=end; e[edgenum].nxt=lnk[bgn]; lnk[bgn]=edgenum; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;++i) { scanf("%d%d",&x,&y); add(x-1,y-1); add(y-1,x-1); } for(int i=0;i<n;++i)f[1<<i][i]=1; for(int k=0;k<(1<<n);++k){ for(int i=0;i<n;++i){ if(!f[k][i])continue; for(int p=lnk[i];p;p=e[p].nxt){ int y=e[p].to; if((k&-k)>(1<<y))continue;//判断起点序 if(k&(1<<y)){ if((k&-k)==(1<<y))//判断环 ans+=f[k][i]; } else f[k|(1<<y)][y]+=f[k][i]; } } } ans=(ans-m)/2; printf("%I64d",ans); return 0; }
[CodeForces 11D] A Simple Task - 状态压缩入门的更多相关文章
- CodeForces - 11D A Simple Task
Discription Given a simple graph, output the number of simple cycles in it. A simple cycle is a cycl ...
- Codeforces 11D A Simple Task 统计简单无向图中环的个数(非原创)
太难了,学不会.看了两天都会背了,但是感觉题目稍微变下就不会了.dp还是摸不到路子. 附ac代码: 1 #include<iostream> 2 #include<cstdio> ...
- Codeforces C. A Simple Task(状态压缩dp)
题目描述: A Simple Task time limit per test 2 seconds memory limit per test 256 megabytes input standar ...
- 计数排序 + 线段树优化 --- Codeforces 558E : A Simple Task
E. A Simple Task Problem's Link: http://codeforces.com/problemset/problem/558/E Mean: 给定一个字符串,有q次操作, ...
- Codeforces 558E A Simple Task (计数排序&&线段树优化)
题目链接:http://codeforces.com/contest/558/problem/E E. A Simple Task time limit per test5 seconds memor ...
- Codeforces 558E A Simple Task(权值线段树)
题目链接 A Simple Task 题意 给出一个小写字母序列和若干操作.每个操作为对给定区间进行升序排序或降序排序. 考虑权值线段树. 建立26棵权值线段树.每次操作的时候先把26棵线段树上的 ...
- Codeforces 580D Kefa and Dishes(状态压缩DP)
题目链接:http://codeforces.com/problemset/problem/580/D 题目大意:有n盘菜每个菜都有一个满意度,k个规则,每个规则由x y c组成,表示如果再y之前吃x ...
- CodeForces 588E A Simple Task(线段树)
This task is very simple. Given a string S of length n and q queries each query is on the format i j ...
- Codeforces J. A Simple Task(多棵线段树)
题目描述: Description This task is very simple. Given a string S of length n and q queries each query is ...
随机推荐
- ASP.NET部分代码示例
using System; using System.Collections.Generic; using Model; using System.Data; using System.Data.Sq ...
- 如何实现vue前端跨域,proxyTable解决开发环境前端跨域问题
在开发环境与后端调试的时候难免会遇到跨域问题,很多人说跨域交给后端解决就好了. 其实不然,前端也有很多方法可以解决跨域,方便也快捷. 常见的有nginx转发.node代理. 在vue项目中常用的是pr ...
- MySQL 中如何存储 emoji ?
MySQL 中如何存储 emoji ? 问题还原 使用 erlang 存储一些特殊字符串到 MySQL 的时候,却没法读出来.经检查,这些字符串的二进制格式如下: <<240,159,15 ...
- DOM生成XML文档
import java.io.File; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuil ...
- 笔记:Struts2 Action 非泛型集合元素类型转换
局部类型转换文件 局部类型转换文件的文件名应为 ActionName-conversion.properties,其中 ActionName 是需要替换为 Action 的类名称,后面的 conver ...
- 【Python】 高级文件操作 shutil
shutil 很多时候,我想要对文件进行重命名,删除,创建等操作的时候的想法就是用subprocess开一个子进程来处理,但是实际上shutil可以更加方便地提供os的文件操作接口,从而可以一条语句搞 ...
- linux --> 系统信息命令
系统信息命令 # uname -a // # 查看内核/操作系统/CPU信息 # head -n /etc/issue // # 查看操作系统版本 # cat /proc/cpuinfo // # 查 ...
- Algorithm --> DFS和BFS
定义结点 struct MGraph { int vexs[MAXVEX]; //顶点数组 int arc[MAXVEX][MAXVEX]; //邻接矩阵 int numVertex, numEdge ...
- Java编程配置思路详解
Java编程配置思路详解 SpringBoot虽然提供了很多优秀的starter帮助我们快速开发,可实际生产环境的特殊性,我们依然需要对默认整合配置做自定义操作,提高程序的可控性,虽然你配的不一定比官 ...
- [UWP]创建一个ProgressControl
1. 前言 博客园终于新增了UWP的分类,我来为这个分类贡献第一篇博客吧. UWP有很多问题,先不说生态的事情,表单.验证.输入.设计等等一堆基本问题缠身.但我觉得最应该首先解决的绝对是Blend,那 ...