• P4929[模板]舞蹈链(DLX)


    正题

    题目链接:https://www.luogu.com.cn/problem/P4929


    题目大意

    \(n*m\)的矩形有\(0/1\),要求选出若干行使得每一列有且仅有一个\(1\)


    解题思路

    精确覆盖问题指的是一个集合\(S\)和它的若干个子集集合\(T\),要求选出\(T\)的一个子集使得里面的集合元素刚好覆盖集合\(S\)
    \(DLX\)全称是\(dancing\ link\ X\),其中\(dancing\ link\)是指交叉十字循环双向链\(X\)是指暴搜。

    知道了这些,就可以去看洛谷题解了(


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=10100;
    int n,m,cnt,l[N],r[N],u[N],d[N],h[N],row[N],col[N],s[N],ans[N];
    void init(){
        for(int i=0;i<=m;i++)
            l[i]=i-1,r[i]=i+1,u[i]=d[i]=i;
        l[0]=m;r[m]=0;cnt=m;
    }
    void link(int x,int y){
        col[++cnt]=y;s[y]++;
        d[cnt]=y;u[cnt]=u[y];
        d[u[y]]=cnt;u[y]=cnt;
        row[cnt]=x;
        if(!h[x])h[x]=l[cnt]=r[cnt]=cnt;
        else{
            l[cnt]=l[h[x]];r[cnt]=h[x];
            r[l[h[x]]]=cnt;l[h[x]]=cnt;
        }
        return;
    }
    void remove(int x){
        r[l[x]]=r[x];l[r[x]]=l[x];
        for(int i=d[x];i!=x;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]]--;
        return;
    }
    void recover(int x){
        for(int i=u[x];i!=x;i=u[i])
            for(int j=l[i];j!=i;j=l[j])
                u[d[j]]=d[u[j]]=j,s[col[j]]++;
        r[l[x]]=l[r[x]]=x;
        return;
    }
    bool dance(int dep){
        if(r[0]==0){
            for(int i=0;i<dep;i++)
                printf("%d ",ans[i]);
            return 1;
        }
        int c=r[0];
        for(int i=c;i!=0;i=r[i])
            if(s[i]<s[c])c=i;
        remove(c);
        for(int i=d[c];i!=c;i=d[i]){
            ans[dep]=row[i];
            for(int j=r[i];j!=i;j=r[j])remove(col[j]);
            if(dance(dep+1))return 1;
            for(int j=l[i];j!=i;j=l[j])recover(col[j]);
        }
        recover(c);
        return 0;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        init();
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++){
                int x;scanf("%d",&x);
                if(x)link(i,j);
            }
        if(!dance(0))
            puts("No Solution!");
        return 0;
    }
    
  • 相关阅读:
    [LeetCode]Sliding Window Maximum
    判断两根线段是否相交
    求幂,我居然又没做出来
    C++集合运算函数总结 & 需要有序集合的操作
    effective stl读书笔记 & stl里面提供的算法 & emplace & ostream_iterator
    利用位操作的几道题目
    C++的new_handler
    TCP的可靠性 窗口滑动 拥塞控制
    关于高性能网络编程的一些知识
    三种连接 & DOS & SYNFLOOD & 防御
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/14247143.html
Copyright © 2020-2023  润新知