首页 > 其他分享 >舞蹈链DLX

舞蹈链DLX

时间:2024-12-06 21:20:51浏览次数:3  
标签:dian 链表 删除 int void 舞蹈 DLX col

算法

算法应用

主要用于精准覆盖问题,通过一点简单的改变就可以直接求重复覆盖问题。

算法流程

  1. 对于当前的矩阵,选择一行,将这一行和不能与这条边一起选的边上的所有点删掉。(不能一起选就是在同一列有点)
  2. 如果删掉后所有列都被删完了,就结束。
  3. 如果这时候还有列没被删,但没有行可以选了就说明不合法,开始回溯,将删去的边加回来。

总结:就是爆搜选的边,但是有一些优化剪枝,不能选矛盾的边。(看到这你会有一种云里雾里的感觉,不明白怎么快速实现,这是正常的,你只需要理解上面是正确的即可)

链表

上面的算法需要我们快速实现删除,回溯以及一些查询。我们考虑到链表是一种支持快速修改的结构,同时易于回溯(因为链表没有真正删除点,只是不经过它而已)。所以用链表实现上述操作。
所以我们引入十字交叉双向循环链表 ,看起来很高级,其实很简单,十字交叉是因为在两条链上,一条是行一条是列。双向就不用说了,循环是为了方便查找。(它就长下面这样子,图来自oi-wiki)
image
将一的信息存下来,为了方便寻找每一列的信息再多存一下列的编号。

代码实现

预处理&建模

void ycl()
{
    for(int i=0;i<=m;i++)
    {
        dian[i].l=i-1;dian[i].r=i+1;
        dian[i].u=i;dian[i].d=i;//有用,竖着的链也要首尾相连
        lcnt[i]=0;//记录每列的1的个数
    }
    cnt=m;
    dian[0].l=m,dian[cnt].r=0;//形成环
    return ;
}
void addnode(int x,int y)
{
    dian[++cnt].row=x;dian[cnt].col=y;//行列信息
    dian[cnt].u=dian[y].u;dian[dian[y].u].d=cnt;
    dian[cnt].d=y;dian[y].u=cnt;
    if(!bk[x])//这一行的第一个1,bk[x]记录了第一个1的编号
    {
        dian[cnt].l=dian[cnt].r=cnt;//左右都没有点,自己成环
        bk[x]=cnt;
    }
    else
    {
        dian[cnt].l=dian[bk[x]].l;dian[dian[bk[x]].l].r=cnt;
        dian[cnt].r=bk[x];dian[bk[x]].l=cnt;
    }
    lcnt[y]++;//记录每列的1的个数
}

删除某一列及相关的东西

void del(int x)
{
    for(int i=dian[x].d;i!=x;i=dian[i].d)//枚举在这一列是一的行,都要删除
    {
        for(int j=dian[i].r;j!=i;j=dian[j].r)//枚举删除的行上的列
        {
            dian[dian[j].u].d=dian[j].d;
            dian[dian[j].d].u=dian[j].u;
            lcnt[dian[j].col]--;
        }
    }
    dian[dian[x].l].r=dian[x].r;
    dian[dian[x].r].l=dian[x].l;//特殊处理列的编号所在的链
    return ;
}

恢复某一列及相关的东西

与删除相反即可

void rev(int x)
{
    dian[dian[x].l].r=x;
    dian[dian[x].r].l=x;
    for(int i=dian[x].d;i!=x;i=dian[i].d)//枚举删除的行
    {
        for(int j=dian[i].r;j!=i;j=dian[j].r)//枚举删除的行上的列
        {
            dian[dian[j].u].d=j;
            dian[dian[j].d].u=j;
            lcnt[dian[j].col]++;
        }
    }
    return ;
}

dance!!!

bool dance(int dep)//搜索的层数
{
    if(dian[0].r==0)//所有列都被合法删除,有解
    {
        for(int i=1;i<dep;i++)cout<<ans[i]<<' ';
        cout<<'\n';
        return 1;
    }
    int c=dian[0].r;
    for(int i=c;i;i=dian[i].r)//在列的那条链上搜索
        if(lcnt[i]<lcnt[c])c=i;//找最小的列,剪枝
    del(c);//删除列c
    for(int i=dian[c].d;i!=c;i=dian[i].d)//枚举选择的行
    {
        ans[dep]=dian[i].row;
        for(int j=dian[i].r;j!=i;j=dian[j].r)//枚举删除的行上的列
            del(dian[j].col);
        if(dance(dep+1))return 1;          
        for(int j=dian[i].r;j!=i;j=dian[j].r)//恢复删除的行上的列
            rev(dian[j].col);
    }
    rev(c);
    return 0;
}

总代码

#include <bits/stdc++.h>
using namespace std;
const int N=50010;
int n,m,cnt,lcnt[N],bk[N],ans[N];
struct node
{
    int l,r,u,d,row,col;//l,r,u,d分别表示左右上下节点编号,row,col表示所在行列
}dian[N];
void ycl()
{
    for(int i=0;i<=m;i++)
    {
        dian[i].l=i-1;dian[i].r=i+1;
        dian[i].u=i;dian[i].d=i;//是否有用?
        lcnt[i]=0;//记录每列的1的个数
    }
    cnt=m;
    dian[0].l=m,dian[cnt].r=0;//形成环
    return ;
}
void addnode(int x,int y)
{
    dian[++cnt].row=x;dian[cnt].col=y;
    dian[cnt].u=dian[y].u;dian[dian[y].u].d=cnt;
    dian[cnt].d=y;dian[y].u=cnt;
    if(!bk[x])//这一行的第一个1,bk[x]记录了第一个1的编号
    {
        dian[cnt].l=dian[cnt].r=cnt;//左右都没有点,自己成环
        bk[x]=cnt;
    }
    else
    {
        dian[cnt].l=dian[bk[x]].l;dian[dian[bk[x]].l].r=cnt;
        dian[cnt].r=bk[x];dian[bk[x]].l=cnt;
    }
    lcnt[y]++;//记录每列的1的个数
}
void del(int x)
{
    for(int i=dian[x].d;i!=x;i=dian[i].d)//枚举删除的行
    {
        for(int j=dian[i].r;j!=i;j=dian[j].r)//枚举删除的行上的列
        {
            dian[dian[j].u].d=dian[j].d;
            dian[dian[j].d].u=dian[j].u;
            lcnt[dian[j].col]--;
        }
    }
    dian[dian[x].l].r=dian[x].r;
    dian[dian[x].r].l=dian[x].l;
    return ;
}
void rev(int x)
{
    dian[dian[x].l].r=x;
    dian[dian[x].r].l=x;
    for(int i=dian[x].d;i!=x;i=dian[i].d)//枚举删除的行
    {
        for(int j=dian[i].r;j!=i;j=dian[j].r)//枚举删除的行上的列
        {
            dian[dian[j].u].d=j;
            dian[dian[j].d].u=j;
            lcnt[dian[j].col]++;
        }
    }
    return ;
}
bool dance(int dep)//搜索的层数
{
    if(dian[0].r==0)//所有列都被合法删除,有解
    {
        for(int i=1;i<dep;i++)cout<<ans[i]<<' ';
        cout<<'\n';
        return 1;
    }
    int c=dian[0].r;
    for(int i=c;i;i=dian[i].r)//在列的那条链上搜索
        if(lcnt[i]<lcnt[c])c=i;//找最小的列
    del(c);//删除列c
    for(int i=dian[c].d;i!=c;i=dian[i].d)//枚举删除的行
    {
        ans[dep]=dian[i].row;
        for(int j=dian[i].r;j!=i;j=dian[j].r)//枚举删除的行上的列
            del(dian[j].col);
        if(dance(dep+1))return 1;          
        for(int j=dian[i].r;j!=i;j=dian[j].r)//恢复删除的行上的列
            rev(dian[j].col);
    }
    rev(c);
    return 0;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    cin>>n>>m;
    ycl();//处理head和列号
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            int x;cin>>x;
            if(x==1)addnode(i,j);//建节点
        }
    
    if(!dance(1))cout<<"No Solution!"<<'\n';
    return 0;
}

应用

标签:dian,链表,删除,int,void,舞蹈,DLX,col
From: https://www.cnblogs.com/storms11/p/18591443

相关文章

  • SSM舞蹈房管理系统lq4q8 在线咨询
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表系统内容:学员,老师,舞蹈课程,课程类型,舞种咨询,咨询回复,课程预约,学员卡开题报告内容一、选题背景与意义随着舞蹈艺术的普及和受欢迎程度的提升,舞蹈房的数量......
  • Binary Search 二分查找算法:逻辑的舞蹈,二分法的精准步伐
    BinarySearch二分查找算法:逻辑的舞蹈,二分法的精准步伐二分查找算法,也称为二分搜索算法(BinarySearch),是一种在有序数组中查找特定元素的高效算法。它通过反复将搜索区间减半来快速定位目标值。二分查找算法的效率远高于线性搜索,因为它每次比较都能排除掉一半的搜索空间。......
  • Java、python、php版 舞蹈工作室管理系统 舞蹈课程预约平台(源码、调试、LW、开题、PPT
    ......
  • Minirobot 双足舞蹈机器人
                                            MF-17ST机器人 产品介绍MF-17ST机器人是一款高度灵活的仿人机器人,它拥有17个自由度,能够精确地模仿人类的基本动作,如行走、转身、弯腰、单腿站立、......
  • ssm基于MVC的舞蹈网站的设计与实现+vue
    摘要随着科学技术的飞速发展,社会的方方面面、各行各业都在努力与现代的先进技术接轨,通过科技手段来提高自身的优势,舞蹈网站当然也不能排除在外。舞蹈网站是以实际运用为开发背景,运用软件工程开发方法,采用Java技术构建的一个管理系统。整个开发过程首先对软件系统进行需......
  • 基于Java+MySQL+SSM舞蹈网站
    系列文章目录项目介绍开发环境系统实现论文参考项目介绍舞蹈作为一种艺术形式,不仅具有娱乐性,还有助于身心健康的发展。近年来,随着人们生活水平的提高和文化素养的增强,舞蹈文化逐渐普及并受到广大民众的喜爱。然而,传统的舞蹈教学方式和宣传渠道存在一定的局限性,难以满足......
  • 300部幼儿园儿歌舞蹈视频大合集,家有萌娃必备
    亲爱的家长朋友们,您是否正在寻找适合您孩子的有趣活动,既能激发他们的艺术天赋,又能让他们在快乐中成长?我们为您精心准备了一个包含300部作品的幼儿园儿歌舞蹈视频大合集,让您的萌娃在家也能享受幼儿园的乐趣!《你好你好》教会孩子们见面时的礼貌用语,通过活泼的舞蹈动作,让孩子们学......
  • 螺旋转动,矩阵的舞蹈:JavaScript中实现螺旋矩阵遍历算法
    螺旋转动,矩阵的舞蹈:JavaScript中实现螺旋矩阵遍历算法基础概念:什么是螺旋矩阵?核心算法解析示例一:基础螺旋矩阵遍历算法解析进阶技巧示例二:动态生成螺旋矩阵技巧点实战与性能优化问题与解决:大矩阵处理结语与讨论在编程的奇幻世界里,数组与矩阵是构筑数字城堡的基石......
  • 基于SpringBoot的舞蹈工作室系统的设计与实现(期末大作业)+附源码+数据库
      摘要当代互联网的迅速发展以及疫情导致的社会环境的变化,传统型的舞蹈工作室教学管理模式已经满足不了学生的需求,在信息型便捷式的社会中,人类的生活环境、工作速度越来越快,因此我们需要不断的面对新涌出来的知识、新技术。为了适应社会的需求,跟上时代的步伐。而舞蹈工作室......
  • P1878 舞蹈课
    原题链接题解1.朴素想法:链表存储+每次遍历一遍找出最小对缺点:时间复杂度过高改进措施:每次遍历一遍,只会挑走一对,剩下的会重复遍历,所以我们把所有的对都找出来放进堆里,每次挑出第一个没有被用到过的对注意审题code#include<bits/stdc++.h>usingnamespacestd;structnode......