一些链接:

    http://www.cnblogs.com/-sunshine/p/3358922.html

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

1、hust 1017 Exact cover (Dancing Links 模板题)

  题意:n*m的单位矩阵。现在要选一些行,使得这些行的集合中每列只出现一个1.

  思路:裸的精确覆盖问题。刷一遍模板。

  1 #include <iostream>  
  2 #include <stdio.h>  
  3 #include <string.h>  
  4 //精确覆盖问题的定义:给定一个由0-1组成的矩阵,是否能找到一个行的集合,使得集合中每一列都恰好包含一个1
  5 const int MN = 1005;//最大行数
  6 const int MM = 1005;//最大列数
  7 const int MNN = 1e5 + 5 + MM; //最大点数  
  8 
  9 struct DLX
 10 {
 11     int n, m, si;//n行数m列数si目前有的节点数  
 12     //十字链表组成部分  
 13     int U[MNN], D[MNN], L[MNN], R[MNN], Row[MNN], Col[MNN];
 14     //第i个结点的U向上指针D下L左R右,所在位置Row行Col列  
 15     int H[MN], S[MM]; //记录行的选择情况和列的覆盖情况  
 16     int ansd, ans[MN];
 17     void init(int _n, int _m)  //初始化空表  
 18     {
 19         n = _n;
 20         m = _m;
 21         for (int i = 0; i <= m; i++) //初始化第一横行(表头)  
 22         {
 23             S[i] = 0;
 24             U[i] = D[i] = i;      //目前纵向的链是空的  
 25             L[i] = i - 1;
 26             R[i] = i + 1;         //横向的连起来  
 27         }
 28         R[m] = 0; L[0] = m;
 29         si = m;                 //目前用了前0~m个结点  
 30         for (int i = 1; i <= n; i++)
 31             H[i] = -1;
 32     }
 33     void link(int r, int c)    //插入点(r,c)  
 34     {
 35         ++S[Col[++si] = c];     //si++;Col[si]=c;S[c]++;  
 36         Row[si] = r;//si该结点的行数为r
 37         D[si] = D[c];//向下指向c的下面的第一个结点
 38         U[D[c]] = si;//c的下面的第一个结点的上面为si
 39         U[si] = c;//si的上面为列指针
 40         D[c] = si;//列指针指向的第一个该列中的元素设为si
 41         if (H[r]<0)//如果第r行没有元素
 42             H[r] = L[si] = R[si] = si;
 43         else
 44         {
 45             R[si] = R[H[r]];//si的右边为行指针所指的右边第一个元素
 46             L[R[H[r]]] = si;//行指针所指的右边第一个元素的左侧为si
 47             L[si] = H[r];//si的左侧为行指针
 48             R[H[r]] = si;//行指针的右侧为si
 49         }
 50     }
 51     void remove(int c)        //列表中删掉c列  
 52     {
 53         L[R[c]] = L[c];//表头操作  //c列头指针的右边的元素的左侧指向c列头指针左边的元素
 54         R[L[c]] = R[c];//c列头指针的左边的元素的右侧指向c列头指针右边的元素
 55         for (int i = D[c]; i != c; i = D[i])//遍历该列的所有元素
 56             for (int j = R[i]; j != i; j = R[j])
 57             {//对于该列的某个元素所在的行进行遍历
 58                 U[D[j]] = U[j];//把该元素从其所在列中除去
 59                 D[U[j]] = D[j];
 60                 --S[Col[j]];//该元素所在的列数目减一
 61             }
 62     }
 63     void resume(int c)        //恢复c列  
 64     {
 65         for (int i = U[c]; i != c; i = U[i])//枚举该列元素
 66             for (int j = L[i]; j != i; j = L[j])//枚举该列元素所在的行
 67                 ++S[Col[U[D[j]] = D[U[j]] = j]];//D[U[j]]=j;U[D[j]]=j;S[Col[j]]++;
 68         L[R[c]] = R[L[c]] = c;//c列头指针左右相连
 69     }
 70     bool dance(int d) //选取了d行  
 71     {
 72         if (R[0] == 0)//全部覆盖了  
 73         {
 74             //全覆盖了之后的操作  
 75             ansd = d;
 76             return 1;
 77         }
 78         int c = R[0];//表头结点指向的第一个列
 79         for (int i = R[0]; i != 0; i = R[i])//枚举列头指针
 80             if (S[i]<S[c])//找到列中元素个数最少的
 81                 c = i;
 82         remove(c);//将该列删去
 83         for (int i = D[c]; i != c; i = D[i])
 84         {//枚举该列的元素
 85             ans[d] = Row[i];//记录该列元素的行
 86             for (int j = R[i]; j != i; j = R[j])
 87                 remove(Col[j]);//将该列的某个元素的行上的元素所在的列都删去
 88             if (dance(d + 1))
 89                 return 1;
 90             for (int j = L[i]; j != i; j = L[j])
 91                 resume(Col[j]);
 92         }
 93         resume(c);
 94         return 0;
 95     }
 96 }dlx;
 97 
 98 int main()
 99 {
100     int n, m;
101     while (scanf("%d%d", &n, &m) != EOF)
102     {
103         dlx.init(n, m);
104         for (int i = 1; i <= n; i++)
105         {//共n列
106             int k;
107             scanf("%d", &k);//每列中含1的个数
108             while (k--)
109             {
110                 int cc;
111                 scanf("%d", &cc);//输入其所在的列
112                 dlx.link(i, cc);//链接
113             }
114         }
115         dlx.ansd = -1;
116         if (dlx.dance(0))
117         {
118             printf("%d", dlx.ansd);
119             for (int i = 0; i<dlx.ansd; i++)
120                 printf(" %d", dlx.ans[i]);
121             printf("\n");
122         }
123         else
124             printf("NO\n");
125     }
126     return 0;
127 }
View Code

相关文章:

  • 2022-01-29
  • 2022-12-23
  • 2022-02-25
  • 2021-10-30
  • 2021-12-09
  • 2022-12-23
  • 2022-12-23
  • 2021-10-06
猜你喜欢
  • 2021-06-29
  • 2022-12-23
  • 2021-12-05
  • 2021-04-09
  • 2021-06-07
  • 2021-05-04
相关资源
相似解决方案