浅谈舞蹈链

舞蹈链解决精确覆盖问题
一、问题引入:
有n 个人, 每个人有一些想吃的菜. 只有你给这个人所有他想吃的菜,他才会吃.
可是你只有m 种菜, 每样一份.你必需把菜卖完. 问最多能满足多少人.
*精确覆盖问题的定义:给定一个由0-1组成的矩阵,是否能找到一个行的集合,使得集合中每一列都恰好包含一个1
假设有5种菜,4个人 ,1表示他喜欢吃这种菜。
(1)0 1 0 1 0
(2)1 0 0 0 0
(3)1 1 1 0 0
(4)0 0 1 0 1
可见最多满足第1 、2 、4。
答案得出的过程。
Step1:我们假设先满足第一人,那么第3人是不能选的(因为每种菜只有一份,3不能和1抢第二种菜)。
Step2: 接着选择第2个人,很完美,两人都可以满足。
Step3:接着选第4个人(第三个人在Step1就淘汰了。)也可以满足他。
这个例子太好了,换一下。
(1)0 0 1 0 1
(2)1 1 1 0 1
(3)0 0 1 1 1
(4)0 0 1 1 1
Step1:发现要覆盖第一列,必须满足第二个人。由于1.3.4人和2都喜欢吃第3种菜,所以都不能满足。
所以只能满足第二个人。但是这时菜不能完全卖完,此问题无解。
总结一下求解的过程:
(1)选择任意一行。
(2)删除选择这一行后不能选择的其他行。
(3)继续选择
(4)若最后没有可选择的行,但是没有完全覆盖,回到第(1)步,修改之前任意选择的行重复步骤。
到这挺好理解的...
二、
发现这过程需要存储矩阵和回溯的过程。那么怎样做比较高效呢。
舞蹈链是一种数据结构,缓存和回溯中效率惊人。不需要额外空间,接近于线性的时间,指针在数据之间
跳跃着,像舞蹈一样所以称之为舞蹈链。(dancing links).
舞蹈链用的数据结构是十字链表。
我们先从双向链表过渡到十字链表吧。
(1)双向链表
A1 A2 A3,
A1.right=A2,A2.left=A1,A3.right.right=A1.
在很多实际运用中,把双向链的首尾相连,构成循环双向链.
删除A2时,A1.right=A3,A3.left=A1,注意A2只是从双向链表中删除了,但是A2的left和right的信息并没有变。
由于不需要开空间,时间也是挺快的。
(2)接下来是双向十字链表。
每个元素有四个指针,left,right,up,down.

注意链首和链尾是双向连接的,一定要注意双向。
列首有我们虚构的点,在第0行,这是为了方便搜索,以后代码呈现。

三、用法。

删除和恢复元素。(先了解后看代码)

规则:

沿列删除时删除左右, 保留上下.
沿行删除时删除上下, 保留左右.
恢复时依然沿之前的方向, 根据自己的信息把自己插进去

四、

那么开始的问题引入,我们怎么用舞蹈链来解决呢。

........................................................假装你思考过了的样子.........................orz

首先每一行的行首表示每个人,列表示每个人爱吃的菜,然后求精确覆盖就可以啦。

五、code

当然很恶心。

int l[maxn],r[maxn],u[maxn],d[maxn],tn,ren[maxn],cai[maxn];
void shanchu(int x) {
    for(int p=r[x]; p!=x; p=r[p]) {
        for(int q=u[p]; q!=p; q=u[q]) {
            for(int s=r[q]; s!=q; s=r[s]) {
                if(d[x]!=s) {
                    d[u[s]]=d[s];
                    u[d[s]]=u[s];
                }
            }
        }
    }
}
void huifu(int x) {
    for(int p=l[x]; p!=x; p=l[p]) {
        for(int q=d[p]; q!=p; q=d[q]) {
            for(int s=l[q]; s!=q; s=l[s]) {
                u[d[s]]=d[u[s]]=s;
            }
        }
    }
}
int main() {
    memset(cai,0,sizeof(cai));
    scanf("%d%d",&n,&m);
    ren[0]=tn=1;
    l[1]=r[1]=1;
    d[1]=u[1]=1;
    for(int i = 1; i <= n; i++) {
        ren[i]=++tn;
        l[tn]=r[tn]=tn;//左右方向建表
        d[ren[i-1]]=tn;//上下方向
        u[tn]=ren[i-1];
        d[tn]=1;//指向列首。
        u[1]=tn//列首指向列尾。
             int totcai,caii,lastcai=tn;
        scanf("%d",&totcai);
        for(int j = 0; j < totcai; ++ j) {
            scanf("%d", &caii);
            ++tn;
            r[last = tn;
              l[tn] = lastcai;
              r[tn]=ren[i];
              l[ren[i]]=tn;
              lastcai = tn;
            if(!cai[caii]) { //cai数组指的是caii最后一次出现的位置编号。
            cai[caii]=u[tn]=d[tn]=tn;
            } else {
                u[tn]=cai[caii];
                d[tn]=d[cai[caii]];
                u[d[tn]]=tn;
                d[u[tn]]=tn;
                cai[caii]=tn;
            }
        }
    }
}
时间: 2024-11-06 09:28:35

浅谈舞蹈链的相关文章

浅谈区块链:密码朋克运动与区块链发展之路

在之前的文章我们都了解到了比特币是如何诞生的,那么是因为中本聪的突发奇想,啪的一下,就诞生了吗?肯定不是啊!今天我们来探究一下比特币诞生背后的渊源. 区块链的技术和文化根源就是密码朋克运动. 那么密码朋克的起源是什么呢? 应该是1970年代,1970年代密码学完全是军火,老百姓是完全接触不到的,商业公司也是接触不到的.直到1970年代,IBM跑去找美国政府,说我们商业公司某些场合也需要使用密码学.因此美国政府批准 IBM 拿出了一个商用密码方案,后来变成了我们今天知道的DES--美国数据加密的标

浅谈树链剖分(C++、算法、树结构)

关于数链剖分我在网上看到的有几个比较好的讲解,本篇主要是对AC代码的注释(感谢各位witer的提供) 这是讲解 http://www.cnblogs.com/kuangbin/archive/2013/08/15/3259083.html 另一个是百度文库 http://wenku.baidu.com/link?url=DY8CAbwdjitIiv8XQsHmVPi--dQAqw5z6dc_6N1Plh4u5Nfc1aCADQm4oAvt4Sqe1mXSixezzK4lRxofQKMX9cNzJ

浅谈区块链技术在商业领域的应用

近年来,由于虚拟数字货币炒作的火爆,作为其底层技术的区块链也开始受到广泛关注.区块链具有去中心化.去信任.集体维护.可靠存储的特征,目前己在虚拟货币领域广泛应用. 自比特币诞生以来,目前全球已陆续出现了 1600多种虚拟货币,围绕着虚拟货币的生成.存储.交易等形成了庞大的产业链生态.但整体而言,行业尚处于初创期,离真正的价值应用区域还有很大距离.区块链经济的核心在于商业逻辑和组织形态的重构,因此需要在多个行业获得应用落地的实例来表明其价值.本文将从区块链与行业需求相结合的角度,探讨区块链在各行业

浅谈树链剖分

今天刚学会树剖......(是不是觉得我很菜QwQ) 树剖的用处: 引子问题1: 给你一颗树,支持两种操作: 1.给x到y路径上的值加z 2.求出点x的值 简单,树上差分嘛,前几天刚学过啊. 引子问题2: 给你一颗树,支持两种操作: 1.给以x为根的子树加z 2.求出以x为根的子树的和. 简单,dfs序+线段树啊. 那么把两个问题结合起来呢?——树链剖分华丽丽登场!!! 树剖核心思想: 听说线段树挺好用的,区改区查只要log的复杂度,但是只能在线性结构上用,哎,真是太遗憾了. 听说有一种叫做df

金猫kinmall:浅谈区块链通证的激励设置

当前,大多数的1CO都意图将项目融资和网络参与强行打包塞进一种通证中,这就形成了通证激励. 您需要在您所希望看到的参与者的短期表现(持有通证以维护其早期价值)和长期表现(大量花费并赚取通证)之间进行权衡.这些校准问题没有明确的最佳实践,因此,这是发生在区块链上的最有趣的实验. 从事风投五年后,我认为1CO的项目融资方是很重要的,但他们可能缺乏创新.它可能会模仿现有的结构,受到各种IPO.私募和风险投资的启发.区块链呈现的真正机会在于使用某种通证或某种协议的分层激励结构,以促使网络保持长期稳定.

蒟蒻浅谈树链剖分之一——两个dfs操作

树链剖分,顾名思义就是将树形的结构剖分成链,我们以此便于在链上操作 首先我们需要明白在树链剖分中的一些概念 重儿子:某节点所有儿子中子树最多的儿子 重链:有重儿子构成的链 dfs序:按重儿子优先遍历时的顺序 轻儿子的意思就与重儿子相反 首先是第一个dfs操作 在本次操作中,我们主要做的是处理所有节点的父亲,子树大小,重儿子,深度等操作 void dfs1(int now,int father,int deep) { tree[now].depth=deep;//初始化当前节点的深度,子树大小,父

泛圈科技:浅谈区块链未来的发展如何?

今天的社会每天都在高速发展,网络与科技不断进步创新时时刻刻都在改变我们身边的生活.每天这个世界的变化都是日新月异,迈入2019年,网络的技术革新步伐更是颠覆我们原有的认知.今年以来 ,以比特币为首的加密货币不断创新高,也另的越来越多的人关注区块链技术在网络应用地位. 比特币以及其他加密数字货币在市场的强势走高,虽然有着市场对这个行业的炒作,但是也意味区块链产业不断的发展,区块链技术也逐渐从学术界应用到产业界中.而在8月份,中央更是出现文件支持深圳开展数字货币研究与移动支付等创新应用,关于区块链数

浅谈区块链和p2p网络

最近对区块链产生了兴趣就去了解了一下,分享一下.... 首先要先了解一下什么叫做区块链: 区块链:简单来说就是一种基于分布式数据存储.点对点传输.共识机制.加密算法等计算机技术的新型应用模式. 相信说到比特币大家都了解,比特币就是基于区块链的基础上而生的.区块链就像是一个去中心化的数据库,是一串使用密码学方法相关联产生的数据块,其中包含了一次比特币网络交易的信息,用于验证其信息的有效性和生成下一个区块.. p2p网络: 对等网络,即对等计算机网络,是一种在对等者(Peer)之间分配任务和工作负载

浅谈建材类型的网站应该选择哪些有效的外链平台

随着互联网的发展,SEO行业在不断的被人们所熟知,从一个普通的公司到一个中小型的企业都在使用SEO来优化网站,可想而知SEO这门技术已经被企业所重视,近期,笔者一直在负责优化建材类型的企业网站,从结构优化到页面优化到内容优化再到外链建设这块,笔者总结出了不少经验心得,然而对外链这方面因百度绿萝算法让笔者优化的思路出现了短路,后来跟一些同行的站长们交流了下并实战了下,发现对建材类网站的效果不错,然后总结出了四个对外链建设有用的方法,下面就由笔者跟各位建材网站的站长们浅谈下建材类型的网站应该选择哪些