状态压缩/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之间有边,状态的转移有以下几种条件:
  1. 若当前状态的起点序大于当前节点 (k&-k>(1<<y)) ,不转移。
  2. 若当前状态经过了当前节点 (k&(1<<y)) ,判断起点是否就是当前节点,若是,意味着我们找到了环,更新答案。
  3. 若当前状态没有经过当前节点,则更新经过当前节点的状态 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 - 状态压缩入门的更多相关文章

  1. CodeForces - 11D A Simple Task

    Discription Given a simple graph, output the number of simple cycles in it. A simple cycle is a cycl ...

  2. Codeforces 11D A Simple Task 统计简单无向图中环的个数(非原创)

    太难了,学不会.看了两天都会背了,但是感觉题目稍微变下就不会了.dp还是摸不到路子. 附ac代码: 1 #include<iostream> 2 #include<cstdio> ...

  3. Codeforces C. A Simple Task(状态压缩dp)

    题目描述:  A Simple Task time limit per test 2 seconds memory limit per test 256 megabytes input standar ...

  4. 计数排序 + 线段树优化 --- Codeforces 558E : A Simple Task

    E. A Simple Task Problem's Link: http://codeforces.com/problemset/problem/558/E Mean: 给定一个字符串,有q次操作, ...

  5. Codeforces 558E A Simple Task (计数排序&&线段树优化)

    题目链接:http://codeforces.com/contest/558/problem/E E. A Simple Task time limit per test5 seconds memor ...

  6. Codeforces 558E A Simple Task(权值线段树)

    题目链接  A Simple Task 题意  给出一个小写字母序列和若干操作.每个操作为对给定区间进行升序排序或降序排序. 考虑权值线段树. 建立26棵权值线段树.每次操作的时候先把26棵线段树上的 ...

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

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

  8. 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 ...

  9. Codeforces J. A Simple Task(多棵线段树)

    题目描述: Description This task is very simple. Given a string S of length n and q queries each query is ...

随机推荐

  1. Ubuntu Mininet环境搭建

    我们通过源码方式搭建mininet仿真平台,使用git下载mininet源码 git clone git://github.com/mininet/mininet 下载完成之后,使用下面命令选择安装版 ...

  2. PHP教程-防止网站被刷票的小技巧

    在Web开发中,投票模块会经常出现.这样就使得防止刷票,成了至关重要的技术.以下是兄弟连教育www.itxdl.cn总结的一些防止刷票方法: 1. IP限制 这是使用的最多,也是最广泛,不可少的刷票限 ...

  3. MySQL数据库学习三 数据库对象和基本操作

    3.1 数据库和数据对象 1. 系统数据库 information_schema:主要存储系统中的一些数据库对象信息,如用户列表信息.列信息.权限信息.字符集信息和分区信息等. performance ...

  4. java-线程实现方式

    实现方式: 1,继承Thread类 public class ThreadTest extends Thread { @Override public void run() { System.out. ...

  5. nuxt 的一些报错和插件推荐

    1.项目有启动报这个错误的,是因为node版本太低了,nuxt要求node版本要达到8.0.0以上 . 2.插件推荐

  6. 获取dmp文件的schema

    白天的时候,做了一个获取dmp文件的schema实验,特此记录一下. 参考文章:如何获取dmp文件的schema  -- by 我的烟灰缸 http://oradb.cc/2017/07/10/%E5 ...

  7. JS图片更换还原操作,通过图片识别标识

    //图片更换还原操作,图片识别标识 如图片img.png 可换成 img2.png function img_biaoshi(caozuo,img_id, biaoshi) { var img_src ...

  8. chrome浏览器访问google插件

    访问google其实很多时候都是为了搜索资料,本文分享下,chrome浏览器访问google插件 下载地址:http://www.ggfwzs.com/ 1,下载完成后,解压: 如下: 2,打开谷歌浏 ...

  9. 总结随笔(Beta)

    听说 -- beta冲刺总结 beta冲刺成员名单 姓名 学号 负责方向 个人主页 周龙荣 031402543 前端页面.跳转 http://www.cnblogs.com/ZHOULR/ 李家鹏 0 ...

  10. 【审核】检查iOS项目中是否使用了IDFA

    (1)什么是IDFA 关于IDFA,在提交应用到App Store时,iTunes Connect有如下说明: 这里说到检查项目中是否包含IDFA,那如何来对iOS项目(包括第三方SDK)检查是否包含 ...