其他分享
首页 > 其他分享> > 洛谷 P4929 【模板】舞蹈链(DLX)

洛谷 P4929 【模板】舞蹈链(DLX)

作者:互联网

题目链接

DLX例题(洛谷模板题就是省选难度了qwq)。

DLX的具体思想我就不赘述了,网上有很多讲的不错的。下附链接

网站1网站2网站3网站4

AC代码如下(代码思路就看注释吧……)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#define mx 250505 
using namespace std;
int n,m,cnt;
int l[mx],r[mx],u[mx],d[mx],row[mx],col[mx];//定义一个点的左右上下以及行数列数。
int h[mx],s[mx];//一行的第一个数 ,一列有几个数
int ansk[mx];//答案 
inline void Init(int m){//初始化m列。m+1个数,0为head(无实际意义,是最后用来判断的 
    for(int i=0;i<=m;i++){
        r[i]=i+1;
        l[i]=i-1;
        u[i]=d[i]=i; 
    }
    r[m]=0,l[0]=m;
    memset(h,-1,sizeof(h));
    memset(s,0,sizeof(s));
    cnt=m+1;//之后录入的数从m+1的下标开始 
}
inline void link(int R,int C){//插入一个在R行C列的点 
    s[C]++;
    row[cnt]=R,col[cnt]=C;//记录行和列 
    u[cnt]=C;//cnt的上面为c,即1~m 
    d[cnt]=d[C];//cnt的下面是原先C的下面 
    u[d[C]]=cnt;//原先c的下面的上面是cnt 
    d[C]=cnt; //c的下面是cnt。一系列操作即将cnt插入C和C下面一个数之间,让cnt成为最接近c的那个数(这样写的话最终其实u是在下面的意思的感觉……
    if(h[R]==-1)//如果这一行没有数的话就将该数作为第一个数录入 
        h[R]=r[cnt]=l[cnt]=cnt;
    else{//有数的话 
        r[cnt]=h[R];//将cnt的右边连接到h[R]的左边 
        l[cnt]=l[h[R]];//将cnt的左边连接到h[R]的左边 
        r[l[h[R]]]=cnt;//将原来h[R]的左边连接到cnt的左边 
        l[h[R]]=cnt;//将cnt连接到h[R]的左边(感觉这样写也是左右颠倒的感觉……不过倒是不影响 
    }     
     cnt++;
     return;
}
inline void remove(int C){//删除c列 
    r[l[C]]=r[C],l[r[C]]=l[C];//删除这一列的存在。
    for(int i=d[C];i!=C;i=d[i])//找每个在该列上的数 
        for(int j=r[i];j!=i;j=r[j]){//找该列上的数所在的那行 ,并删除整行 
            u[d[j]]=u[j];
            d[u[j]]=d[j];
            s[col[j]]--;//该数所在列内数量-1
        } 
    return;
} 
inline void resume(int C){
    r[l[C]]=C,l[r[C]]=C;
    for(int i=d[C];i!=C;i=d[i])
        for(int j=r[i];j!=i;j=r[j]){
            u[d[j]]=j;
            d[u[j]]=j;
            s[col[j]]++; 
        }
    return;
} 
bool dance(int deep){
    if(r[0]==0){//如果列删光了且除了head没有元素留下来。则表示该情况成立 
        for(int i=0;i<deep;i++)
            printf("%d ",ansk[i]);
            return 1;
    }
    int c=r[0];
    for(int i=r[0];i!=0;i=r[i])//优先从列中数最少的开始找。缩小查找范围 
        if(s[i]<s[c])
            c=i;
    remove(c);//删除c列 
    for(int i=d[c];i!=c;i=d[i]){//从c列当中选1行进行查找 
        ansk[deep]=row[i];//记录当前被删的行数
        for(int j=r[i];j!=i;j=r[j]) //加上这句话后感觉remove函数中的第三个循环没什么必要的样子…… 
            remove(col[j]);
        if(dance(deep+1))
            return 1;
        for(int j=l[i];j!=i;j=l[j])
            resume(col[j]);
    } 
    resume(c);
    return 0;
}
int main(){
    scanf("%d%d",&n,&m);
    Init(m); 
    char temp;
    int k;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            scanf("%d",&k);
             if(k)
                 link(i,j);
        }
    if(!dance(0))
        printf("No Solution!");
    return 0;
}

 

标签:P4929,洛谷,DLX,int,网站,include,mx
来源: https://www.cnblogs.com/mikku39/p/14453874.html