DLX模板

18 篇文章 0 订阅
1 篇文章 0 订阅

DLX,Dancing Links X算法,用于求解精确覆盖问题

《算法竞赛入门经典——训练指南》P406有很好的介绍

这些博客写得也不错

http://www.cnblogs.com/grenet/p/3145800.html

http://blog.csdn.net/sunny606/article/details/7833551



struct DLX
{
    int n,sz;//列数,结点数
    int S[maxc];//各列结点数
    int row[maxnode],col[maxnode];//各点行列编号
    int L[maxnode],R[maxnode],U[maxnode],D[maxnode];//十字链表
    int ansd,ans[maxr];//解

    void init(int n)
    {
        this->n=n;

        //虚拟结点
        for (int i=0;i<=n;i++)
        {
            U[i]=i;D[i]=i;L[i]=i-1;R[i]=i+1;
        }

        R[n]=0;L[0]=n;
        sz=n+1;
        memset(S,0,sizeof S);
    }

    //插入决策行  _r 行号  columns 记录结点列号·[1,n]
    void add_row(int _r,vector<int> columns)
    {
        int first=sz;
        for (int i=0;i<columns.size();i++)
        {
            int _c=columns[i];
            L[sz]=sz-1;R[sz]=sz+1;
            D[sz]=_c;U[sz]=U[_c];//成环
            D[U[_c]]=sz;U[_c]=sz;
            row[sz]=_r;col[sz]=_c;
            S[_c]++;sz++;
        }
        R[sz-1]=first;L[first]=sz-1;
    }

    //删除一列结点
    void _remove(int _c)
    {
        L[R[_c]]=L[_c];
        R[L[_c]]=R[_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]]--;
            }
    }

    //恢复一列结点,和删除顺序相反
    void _resume(int _c)
    {
        for (int i=U[_c];i!=_c;i=U[i])
            for (int j=L[i];j!=i;j=L[j])
            {
                U[D[j]]=j;D[U[j]]=j;S[col[j]]++;
            }

        L[R[_c]]=_c;
        R[L[_c]]=_c;
    }

    bool dfs(int d)
    {
        if (R[0]==0)
        {
            ansd=d; //记录解的长度
            return true;
        }

        //找最少结点的列删除
        int _c=R[0];
        for (int i=R[0];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[d]=row[i];
            for (int j=R[i];j!=i;j=R[j])
                _remove(col[j]);

            if (dfs(d+1))   return true;

            for (int j=L[i];j!=i;j=L[j])//反向恢复
                _resume(col[j]);
        }
        _resume(_c);

        return false;
    }

    bool solve(vector<int> &v)
    {
        v.clear();
        if (!dfs(0)) return false;

        for (int i=0;i<ansd;i++)    v.push_back(ans[i]);

        return true;
    }

};


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值