码迷,mamicode.com
首页 > 其他好文 > 详细

kuangbin带我飞QAQ DLX之一脸懵逼

时间:2018-05-09 22:44:55      阅读:220      评论:0      收藏:0      [点我收藏+]

标签:第一个   move   queue   else   color   iostream   #define   als   splay   

hust 1017 模板题

 

勉强写了注释,但还是一脸懵逼,感觉插入方式明显有问题但又不知道哪里不对而且好像能得出正确结果真是奇了怪了

技术分享图片
  1 #include <iostream>
  2 #include <string.h>
  3 #include <cstdio>
  4 #include <queue>
  5 #include <map>
  6 #include <vector>
  7 #include <string>
  8 #include <cstring>
  9 #include <algorithm>
 10 #include <math.h>
 11 
 12 #define SIGMA_SIZE 26
 13 #define lson rt<<1
 14 #define rson rt<<1|1
 15 #pragma warning ( disable : 4996 )
 16 
 17 using namespace std;
 18 typedef long long LL;
 19 inline LL LMax(LL a,LL b)    { return a>b?a:b; }
 20 inline LL LMin(LL a,LL b)    { return a>b?b:a; }
 21 inline int Max(int a,int b) { return a>b?a:b; }
 22 inline int Min(int a,int b) { return a>b?b:a; }
 23 inline int gcd( int a, int b ) { return b==0?a:gcd(b,a%b); }
 24 inline int lcm( int a, int b ) { return a/gcd(a,b)*b; }  //a*b = gcd*lcm
 25 const LL INF = 0x3f3f3f3f3f3f3f3f;
 26 const LL mod  = 1000000007;
 27 const int inf  = 0x3f3f3f3f;
 28 const int maxk = 1e5+5;
 29 const int maxn = 1e4+5;
 30 
 31 
 32 //第一行为虚拟行,是人为加上的,一共有m+1个点(第一个点独立于整个矩阵)
 33 //而后加入的值为1的点标号用size表示
 34 //即第一行一共m+1个点,所以size先从0~m,之后每加入一个为1的点,size++
 35 //大部分数组X都用X[size]来标识标号为size的点的信息
 36 struct DLX {
 37     int n, m, size, fin;
 38     int U[maxn], D[maxn], L[maxn], R[maxn];//上下左右
 39     int head[maxn], S[maxn];                //分别存每一行第一个1的点的标号和每一列1的个数
 40     int row[maxn], col[maxn], ans[maxn];    //row,col表示第size个点在哪一行/列
 41 
 42 
 43     void init( int _n, int _m )
 44     {
 45         n = _n; m = _m;
 46         for ( int i = 0; i <= m; i++ )    //初始化第一行(人为增加的虚拟行)
 47         {
 48             S[i] = 0;
 49             U[i] = D[i] = i;
 50             L[i] = i-1;
 51             R[i] = i+1;
 52         }
 53         R[m] = 0; L[0] = m;        //第一行的最后一个元素指向第一个
 54         size = m;                //从m开始以后都是普通节点
 55         memset( head, -1, sizeof(head) );
 56         head[0] = 0;
 57     }
 58 
 59     void link( int r, int c )
 60     {
 61         size++;                    //得到新的点标号
 62         col[size] = c;            //第size个点在第c列
 63         row[size] = r;            //第size个点在第r行
 64         S[c]++;                    //第c列1的个数+1
 65         
 66         //组成一个环,和下面左右一样的插法
 67         D[size] = D[c];            
 68         U[size] = c;            
 69         U[D[c]] = size;            
 70         D[c] = size;        
 71 
 72         //如果该行没有为1的节点
 73         if ( head[r] < 0 ) head[r] = L[size] = R[size] = size;
 74         else
 75         {
 76             //组成一个环,插在head[r]和head[r]右边那个元素中间
 77             R[size] = R[head[r]];        
 78             L[R[size]] = size;
 79             L[size] = head[r];
 80             R[head[r]] = size;
 81         }
 82     }
 83 
 84     void remove( int c )   //删除列c及其所在行
 85     {
 86         L[R[c]] = L[c]; R[L[c]] = R[c];                //c的左右两个节点互相连接
 87         for ( int i = D[c]; i != c; i = D[i] )        //屏蔽c列
 88             for ( int j = R[i]; j != i; j = R[j] )
 89             {
 90                 U[D[j]] = U[j];
 91                 D[U[j]] = D[j];
 92                 --S[col[j]];        //j所在的列的1的数目数减少
 93             }
 94     }
 95 
 96     void resume( int c )
 97     {
 98         for ( int i = U[c]; i != c; i = U[i] )
 99             for ( int j = L[i]; j != i; j = L[j] )
100             {
101                 col[U[D[j]]] = D[U[j]] = j;
102                 ++S[j];
103             }
104         L[R[c]] = R[L[c]] = c;
105     }
106 
107     bool dance( int d )
108     {
109         if ( R[0] == 0 ) //第0行没有节点
110         {
111             fin = d;
112             return true;
113         }
114 
115         //找出含1数目最小的一列
116         int mark = R[0];
117         for ( int i = R[0]; i != 0; i = R[i] )
118             if ( S[i] < S[mark] )
119                 mark = i;
120 
121         remove(mark);    //移除列mark的1的对应行
122         for ( int i = D[mark]; i != mark; i = D[i] )
123         {
124             ans[d] = row[i];
125             //移除该行的1的对应列
126             for ( int j = R[i]; j != i; j = R[j] )
127                 remove(col[j]);
128 
129             if ( dance(d+1) )
130                 return true;
131 
132             //倒着恢复
133             for ( int j = L[i]; j != i; j = L[i] )
134                 resume(col[j]);
135         }
136         resume(mark);
137         return false;
138     }
139 }dlx;
140 
141 
142 int main()
143 {
144     //freopen("F:\\cpp\\test.txt","r",stdin); 
145 
146     int n, m;
147     while ( ~scanf("%d %d", &n, &m) )
148     {
149         dlx.init(n,m);
150         for ( int i = 1; i <= n; i++ )
151         {
152             int num, j;
153             scanf("%d",&num);
154             while (num--)
155             {
156                 scanf("%d",&j);
157                 dlx.link(i,j);
158             }
159         }
160 
161         if ( dlx.dance(0) )
162         {
163             printf( "%d", dlx.fin );
164             for ( int i = 0; i < dlx.fin; i++ )
165                 printf( " %d", dlx.ans[i] );
166             printf( "\n" );
167             //continue;
168         }
169         else
170             printf("NO\n");
171     }
172     
173     return 0;
174 }
View Code

 

kuangbin带我飞QAQ DLX之一脸懵逼

标签:第一个   move   queue   else   color   iostream   #define   als   splay   

原文地址:https://www.cnblogs.com/chaoswr/p/9016739.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!