标签:第一个 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 }
标签:第一个 move queue else color iostream #define als splay
原文地址:https://www.cnblogs.com/chaoswr/p/9016739.html