zoukankan      html  css  js  c++  java
  • Dancing Link --- 模板题 HUST 1017

     1017 - Exact cover

    Problem's Link:   http://acm.hust.edu.cn/problem/show/1017


    Mean: 

    给定一个由0-1组成的矩阵,是否能找到一个行的集合,使得集合中每一列都恰好包含一个1

    analyse:

    初学DLX。

    这是DLX处理的最简单的问题,也是模板题。

    Time complexity: O(n*d)

    Source code: 

    #include <stdio.h>
    #include <string.h>
    #include <iostream>
    #include <algorithm>
    #include <vector>
    #include <queue>
    #include <set>
    #include <map>
    #include <string>
    #include <math.h>
    #include <stdlib.h>
    #include <time.h>
    using namespace std;
    const int MAXNode = 100010;
    const int MAXN = 1010;
    struct DLX
    {
        int n,m,size;
        int U[MAXNode],D[MAXNode],R[MAXNode],L[MAXNode],Row[MAXNode],Col[MAXNode];
        int H[MAXN], S[MAXN]; // H[i]---第i行第一个为1的index     S[i]---第i列为1的个数
        int ansd, ans[MAXN];
        void init(int _n,int _m)
        {
            n = _n;
            m = _m;
            for(int i = 0;i <= m;i++)  //  初始化第一行(图中的C[])
            {
                S[i] = 0; // 第i列为1的个数
                U[i] = D[i] = i;  
                L[i] = i-1;
                R[i] = i+1;
            }
            R[m] = 0; L[0] = m; // 第一行的最后一个指向第一行的第一个(成环)
            size = m;  // 从m开始以后的都是普通结点
            for(int i = 1;i <= n;i++)
                H[i] = -1;  // H[i]---第i行第一个为1的结点编号
        }
        void Link(int r,int c) // 行  列
        {
            // D[c] --- 第c列的下指针
            S[Col[++size]=c]++; // 普通结点下标++  第size个结点的列数是c    第c列的结点个数++
            Row[size] = r;     // 第size个结点的行数是r
            D[size] = D[c];   // 第size个结点的下指针是:第0行第c列的下指针
            U[size] = c;     // 第size个结点的上指针是:第0行第c列 (只有输入行是递增时才可以这样)
            U[D[c]] = size; // 第0行第c列的上指针是:size
            D[c] = size;   // size上面那个的下指针是:size (有点绕)
            if(H[r] < 0) H[r] = L[size] = R[size] = size; // 该行只有一个结点  左右指针自己指向自己
            else
            {
                R[size] = R[H[r]];  // 成环
                L[R[H[r]]] = size;
                L[size] = H[r];
                R[H[r]] = size;
            }
        }
        void remove(int c)  // 删除列c及其所在的行
        {
            L[R[c]] = L[c]; R[L[c]] = 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]] = U[j];
                    D[U[j]] = D[j];
                    --S[Col[j]]; // j所在的列的数目减少
                }
        }
        void resume(int c)  //恢复列c缩对应的行
        {
            for(int i = U[c];i != c;i = U[i])
                for(int j = L[i];j != i;j = L[j])
                    ++S[Col[U[D[j]]=D[U[j]]=j]];
            L[R[c]] = R[L[c]] = c;
        }
        //d为递归深度
        bool Dance(int d)
        {
            if(R[0] == 0) // R[0]==R[m] // 第0行已经没有结点
            {
                ansd = d;
                return true;
            }
            int c = R[0];
            for(int i = R[0];i != 0;i = R[i]) // 往右走  ( 找出结点数最少的一列)
                if(S[i] < S[c])  //第i列结点个数 < 第c列结点个数
                    c = i;
            remove(c); // 移除列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(Dance(d+1))return true;//递归下一层
                for(int j = L[i]; j != i;j = L[j])resume(Col[j]);//倒着恢复
            }
            resume(c);
            return false;
        }
    };
    
    DLX g;
    int main()
    {
        //freopen("in.txt","r",stdin);
        //freopen("out.txt","w",stdout);
        int n,m;
        while(scanf("%d%d",&n,&m) == 2)
        {
            g.init(n,m);
            for(int i = 1;i <= n;i++) //
            {
                int num,j;
                scanf("%d",&num);
                while(num--)
                {
                    scanf("%d",&j);  //
                    g.Link(i,j);
                }
            }
            if(!g.Dance(0)) printf("NO
    ");
            else
            {
                printf("%d",g.ansd);
                for(int i = 0;i < g.ansd;i++)
                    printf(" %d",g.ans[i]);
                printf("
    ");
            }
        }
        return 0;
    }
    View Code

    这个博客讲得非常细:

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

     

  • 相关阅读:
    UVa OJ 148 Anagram checker (回文构词检测)
    UVa OJ 134 LoglanA Logical Language (Loglan逻辑语言)
    平面内两条线段的位置关系(相交)判定与交点求解
    UVa OJ 130 Roman Roulette (罗马轮盘赌)
    UVa OJ 135 No Rectangles (没有矩形)
    混合函数继承方式构造函数
    html5基础(第一天)
    js中substr,substring,indexOf,lastIndexOf,split等的用法
    css的textindent属性实现段落第一行缩进
    普通的css普通的描边字
  • 原文地址:https://www.cnblogs.com/crazyacking/p/4427300.html
Copyright © 2011-2022 走看看