1. hust 1017 DLX精确覆盖 模板题
勉强写了注释,但还是一脸懵逼,感觉插入方式明显有问题但又不知道哪里不对而且好像能得出正确结果真是奇了怪了
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 U[D[j]] = D[U[j]] = j; 102 ++S[col[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[j] ) 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( " " ); 167 //continue; 168 } 169 else 170 printf("NO "); 171 } 172 173 return 0; 174 }
2. ZOJ 3209 矩阵映射DLX精确覆盖
给一个大矩阵和p个小矩阵,问在p个小矩阵中能否取若干个使它们覆盖整个大矩阵,并且小矩阵间两两互不覆盖。
把大矩阵分为1-n*m个小块(就是横竖切割n和m次),则题目的要求就变成了每个小块都要被一个且仅能有一个小矩阵覆盖,然后就是映射了,因为每个小矩阵能覆盖1~n*m这么多编号小块中的某些块,那么我们让每个小矩阵为1行,并设n*m列,则题目就变成p行n*m列的矩阵对其求精确覆盖了
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 = 1e5; 30 31 struct DLX { 32 int n, m, size, fin; 33 int U[maxn], D[maxn], L[maxn], R[maxn]; //上下左右 34 int head[maxn], S[maxn]; //分别存每一行第一个1的点的标号和每一列1的个数 35 int row[maxn], col[maxn], ans[maxn]; //row,col表示第size个点在哪一行/列 36 37 38 void init( int _n, int _m ) 39 { 40 n = _n; m = _m; 41 for ( int i = 0; i <= m; i++ ) //初始化第一行(人为增加的虚拟行) 42 { 43 S[i] = 0; 44 U[i] = D[i] = i; 45 L[i] = i-1; 46 R[i] = i+1; 47 } 48 R[m] = 0; L[0] = m; //第一行的最后一个元素指向第一个 49 fin = -1; size = m; //从m开始以后都是普通节点 50 memset( head, -1, sizeof(head) ); 51 } 52 53 void link( int r, int c ) 54 { 55 size++; //得到新的点标号 56 col[size] = c; //第size个点在第c列 57 row[size] = r; //第size个点在第r行 58 S[c]++; //第c列1的个数+1 59 60 //组成一个环,和下面左右一样的插法 61 D[size] = D[c]; 62 U[size] = c; 63 U[D[c]] = size; 64 D[c] = size; 65 66 //如果该行没有为1的节点 67 if ( head[r] < 0 ) head[r] = L[size] = R[size] = size; 68 else 69 { 70 //组成一个环,插在head[r]和head[r]右边那个元素中间 71 R[size] = R[head[r]]; 72 L[R[size]] = size; 73 L[size] = head[r]; 74 R[head[r]] = size; 75 } 76 } 77 78 void remove( int c ) //删除列c及其所在行 79 { 80 L[R[c]] = L[c]; R[L[c]] = R[c]; //c的左右两个节点互相连接 81 for ( int i = D[c]; i != c; i = D[i] ) //屏蔽c列 82 for ( int j = R[i]; j != i; j = R[j] ) 83 { 84 U[D[j]] = U[j]; 85 D[U[j]] = D[j]; 86 --S[col[j]]; //j所在的列的1的数目数减少 87 } 88 } 89 90 void resume( int c ) 91 { 92 for ( int i = U[c]; i != c; i = U[i] ) 93 for ( int j = L[i]; j != i; j = L[j] ) 94 { 95 U[D[j]] = D[U[j]] = j; 96 ++S[col[j]]; 97 } 98 L[R[c]] = R[L[c]] = c; 99 } 100 101 void dance( int d ) 102 { 103 if ( fin != -1 && fin <= d ) 104 return; 105 if ( R[0] == 0 ) //第0行没有节点 106 { 107 fin = d; 108 return; 109 } 110 111 //找出含1数目最小的一列 112 int mark = R[0]; 113 for ( int i = R[0]; i != 0; i = R[i] ) 114 if ( S[i] < S[mark] ) 115 mark = i; 116 117 remove(mark); //移除列mark的1的对应行 118 for ( int i = D[mark]; i != mark; i = D[i] ) 119 { 120 ans[d] = row[i]; 121 //移除该行的1的对应列 122 for ( int j = R[i]; j != i; j = R[j] ) 123 remove(col[j]); 124 125 dance(d+1); 126 127 //倒着恢复 128 for ( int j = L[i]; j != i; j = L[j] ) 129 resume(col[j]); 130 } 131 resume(mark); 132 133 return; 134 } 135 }dlx; 136 137 138 int pos[32][32]; 139 140 int main() 141 { 142 freopen("F:\cpp\test.txt","r",stdin); 143 144 int n, m, p; 145 int x1, x2, y1, y2; 146 int T; cin >> T; 147 while (T--) 148 { 149 scanf("%d %d %d", &n, &m, &p); 150 dlx.init(p, n*m); 151 152 int id = 1; 153 for ( int i = 1; i <= n; i++ ) 154 for ( int j = 1; j <= m; j++ ) 155 pos[i][j] = id++; 156 157 for ( int r = 1; r <= p; r++ ) 158 { 159 scanf("%d %d %d %d", &x1, &y1, &x2, &y2); 160 //注意对应的规则 161 for ( int i = x1+1; i <= x2; i++ ) 162 for ( int j = y1+1; j <= y2; j++ ) 163 dlx.link( r, pos[i][j] ); 164 } 165 166 dlx.dance(0); 167 printf("%d ", dlx.fin); 168 } 169 170 return 0; 171 }
懒得修改了...直接贴另一种返回
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 = 1e5; 30 31 struct DLX { 32 int n, m, size, fin; 33 int U[maxn], D[maxn], L[maxn], R[maxn]; //上下左右 34 int head[maxn], S[maxn]; //分别存每一行第一个1的点的标号和每一列1的个数 35 int row[maxn], col[maxn], ans[maxn]; //row,col表示第size个点在哪一行/列 36 37 38 void init( int _n, int _m ) 39 { 40 n = _n; m = _m; 41 for ( int i = 0; i <= m; i++ ) //初始化第一行(人为增加的虚拟行) 42 { 43 S[i] = 0; 44 U[i] = D[i] = i; 45 L[i] = i-1; 46 R[i] = i+1; 47 } 48 R[m] = 0; L[0] = m; //第一行的最后一个元素指向第一个 49 fin = -1; size = m; //从m开始以后都是普通节点 50 memset( head, -1, sizeof(head) ); 51 } 52 53 void link( int r, int c ) 54 { 55 size++; //得到新的点标号 56 col[size] = c; //第size个点在第c列 57 row[size] = r; //第size个点在第r行 58 S[c]++; //第c列1的个数+1 59 60 //组成一个环,和下面左右一样的插法 61 D[size] = D[c]; 62 U[size] = c; 63 U[D[c]] = size; 64 D[c] = size; 65 66 //如果该行没有为1的节点 67 if ( head[r] < 0 ) head[r] = L[size] = R[size] = size; 68 else 69 { 70 //组成一个环,插在head[r]和head[r]右边那个元素中间 71 R[size] = R[head[r]]; 72 L[R[size]] = size; 73 L[size] = head[r]; 74 R[head[r]] = size; 75 } 76 } 77 78 void remove( int c ) //删除列c及其所在行 79 { 80 L[R[c]] = L[c]; R[L[c]] = R[c]; //c的左右两个节点互相连接 81 for ( int i = D[c]; i != c; i = D[i] ) //屏蔽c列 82 for ( int j = R[i]; j != i; j = R[j] ) 83 { 84 U[D[j]] = U[j]; 85 D[U[j]] = D[j]; 86 --S[col[j]]; //j所在的列的1的数目数减少 87 } 88 } 89 90 void resume( int c ) 91 { 92 for ( int i = U[c]; i != c; i = U[i] ) 93 for ( int j = L[i]; j != i; j = L[j] ) 94 { 95 U[D[j]] = D[U[j]] = j; 96 ++S[col[j]]; 97 } 98 L[R[c]] = R[L[c]] = c; 99 } 100 101 bool dance( int d ) 102 { 103 if ( fin != -1 && fin <= d ) 104 return false; 105 if ( R[0] == 0 ) //第0行没有节点 106 { 107 fin = d; 108 return true; 109 } 110 111 //找出含1数目最小的一列 112 int mark = R[0]; 113 for ( int i = R[0]; i != 0; i = R[i] ) 114 if ( S[i] < S[mark] ) 115 mark = i; 116 117 remove(mark); //移除列mark的1的对应行 118 for ( int i = D[mark]; i != mark; i = D[i] ) 119 { 120 ans[d] = row[i]; 121 //移除该行的1的对应列 122 for ( int j = R[i]; j != i; j = R[j] ) 123 remove(col[j]); 124 125 dance(d+1); 126 127 //倒着恢复 128 for ( int j = L[i]; j != i; j = L[j] ) 129 resume(col[j]); 130 } 131 resume(mark); 132 133 return false; 134 } 135 }dlx; 136 137 138 int pos[32][32]; 139 140 int main() 141 { 142 freopen("F:\cpp\test.txt","r",stdin); 143 144 int n, m, p; 145 int x1, x2, y1, y2; 146 int T; cin >> T; 147 while (T--) 148 { 149 scanf("%d %d %d", &n, &m, &p); 150 dlx.init(p, n*m); 151 152 int id = 1; 153 for ( int i = 1; i <= n; i++ ) 154 for ( int j = 1; j <= m; j++ ) 155 pos[i][j] = id++; 156 157 for ( int r = 1; r <= p; r++ ) 158 { 159 scanf("%d %d %d %d", &x1, &y1, &x2, &y2); 160 //注意对应的规则 161 for ( int i = x1+1; i <= x2; i++ ) 162 for ( int j = y1+1; j <= y2; j++ ) 163 dlx.link( r, pos[i][j] ); 164 } 165 166 dlx.dance(0); 167 printf("%d ", dlx.fin); 168 } 169 170 return 0; 171 }
3.HDU 2295 圆形重复覆盖+二分
一脸懵逼逼逼....如果说之前那个模板还勉强看的懂...这个就完全懵逼了(还非常容易写错)。题目比较简单就不说了
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 double eps = 1e-8; 28 const int inf = 0x3f3f3f3f; 29 const int maxk = 1e4; 30 const int maxn = 105; 31 32 struct DLX { 33 int n, m, size, fin; 34 int U[maxk], D[maxk], L[maxk], R[maxk]; 35 int C[maxk]; 36 37 int head[maxk]; 38 int S[maxk]; 39 bool vis[maxk]; 40 41 void init( int _n, int _m ) 42 { 43 n = _n; m = _m; 44 for ( int i = 0; i <= m; i++ ) 45 { 46 U[i] = D[i] = i; 47 L[i] = i-1; 48 R[i] = i+1; 49 S[i] = 0; 50 } 51 L[0] = m; R[m] = 0; 52 size = m; 53 memset( head, -1, sizeof(head) ); 54 } 55 56 void link( int r, int c ) 57 { 58 size++; 59 C[size] = c; 60 S[c]++; 61 62 D[size] = D[c]; 63 U[size] = c; 64 U[D[c]] = size; 65 D[c] = size; 66 67 if ( head[r] < 0 ) 68 head[r] = L[size] = R[size] = size; 69 else 70 { 71 R[size] = R[head[r]]; 72 L[R[size]] = size; 73 L[size] = head[r]; 74 R[head[r]] = size; 75 } 76 } 77 78 void remove( int id ) 79 { 80 for ( int i = D[id]; i != id; i = D[i] ) 81 { 82 L[R[i]] = L[i]; 83 R[L[i]] = R[i]; 84 } 85 } 86 87 void resume( int id ) 88 { 89 for ( int i = D[id]; i != id; i = D[i] ) 90 L[R[i]] = R[L[i]] = i; 91 } 92 93 int h() 94 { 95 int sum = 0; 96 memset( vis, 0, sizeof(vis) ); 97 for ( int i = R[0]; i != 0; i = R[i] ) 98 if (!vis[i]) 99 { 100 sum++; 101 for ( int j = D[i]; j != i; j = D[j] ) 102 for ( int k = R[j]; k != j; k = R[k] ) 103 vis[C[k]] = 1; 104 } 105 return sum; 106 } 107 108 void dance( int k ) 109 { 110 int mark, mmin = inf; 111 if ( k + h() >= fin ) 112 return; 113 if ( R[0] == 0 ) 114 { 115 if ( k < fin ) 116 fin = k; 117 return; 118 } 119 120 for ( int i = R[0]; i != 0; i = R[i] ) 121 if ( mmin > S[i] ) 122 { 123 mmin = S[i]; 124 mark = i; 125 } 126 127 for ( int i = D[mark]; i != mark; i = D[i] ) 128 { 129 remove(i); 130 for ( int j = R[i]; j != i; j = R[j] ) remove(j); 131 dance(k+1); 132 for ( int j = R[i]; j != i; j = R[j] ) resume(j); 133 resume(i); 134 } 135 } 136 }dlx; 137 138 double mmap[maxn][2]; 139 double cir[maxn][2]; 140 141 void init( int n, int m ) 142 { 143 for ( int i = 1; i <= n; i++ ) 144 scanf("%lf %lf", &mmap[i][0], &mmap[i][1]); 145 for ( int i = 1; i <= m; i++ ) 146 scanf("%lf %lf", &cir[i][0], &cir[i][1]); 147 } 148 149 double getdis( int i, int j ) 150 { 151 double a = mmap[i][0] - cir[j][0]; 152 double b = mmap[i][1] - cir[j][1]; 153 a *= a; b *= b; 154 return sqrt(a+b); 155 } 156 157 bool judge( int n, int m, int k, double r ) 158 { 159 dlx.init(m, n); dlx.fin = inf; 160 161 for ( int i = 1; i <= n; i++ ) 162 for ( int j = 1; j <= m; j++ ) 163 { 164 if ( r >= getdis(i,j) ) 165 dlx.link(j,i); 166 } 167 dlx.dance(0); 168 if ( dlx.fin <= k ) return 1; 169 else return 0; 170 } 171 172 int main() 173 { 174 #ifdef local 175 freopen("F:\cpp\test.txt","r",stdin); 176 #endif 177 178 int n, m, k; 179 int T; cin >> T; 180 while (T--) 181 { 182 scanf("%d %d %d", &n, &m, &k); 183 init(n,m); 184 185 double mid, lhs = 0.0, rhs = 1000.0; 186 while ( rhs - lhs > eps ) 187 { 188 mid = (lhs+rhs) / 2; 189 if ( judge(n,m,k,mid) ) 190 rhs = mid; 191 else 192 lhs = mid; 193 } 194 printf("%.6lf ", (lhs+rhs)/2); 195 } 196 return 0; 197 }
4.FZU 1686 矩形重复覆盖
原来DLX主要是考察建模啊,模板实在不想每次都打一遍了...直接ctrl+c
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 double eps = 1e-8; 28 const int inf = 0x3f3f3f3f; 29 const int maxk = 1000; 30 const int maxn = 105; 31 32 struct DLX { 33 int n, m, size, fin; 34 int U[maxk], D[maxk], L[maxk], R[maxk]; 35 int C[maxk]; 36 37 int head[maxk]; 38 int S[maxk]; 39 bool vis[maxk]; 40 41 void init( int _n, int _m ) 42 { 43 n = _n; m = _m; 44 for ( int i = 0; i <= m; i++ ) 45 { 46 U[i] = D[i] = i; 47 L[i] = i-1; 48 R[i] = i+1; 49 S[i] = 0; 50 } 51 L[0] = m; R[m] = 0; 52 fin = inf; size = m; 53 memset( head, -1, sizeof(head) ); 54 } 55 56 void link( int r, int c ) 57 { 58 size++; 59 C[size] = c; 60 S[c]++; 61 62 D[size] = D[c]; 63 U[size] = c; 64 U[D[c]] = size; 65 D[c] = size; 66 67 if ( head[r] < 0 ) 68 head[r] = L[size] = R[size] = size; 69 else 70 { 71 R[size] = R[head[r]]; 72 L[R[size]] = size; 73 L[size] = head[r]; 74 R[head[r]] = size; 75 } 76 } 77 78 void remove( int id ) 79 { 80 for ( int i = D[id]; i != id; i = D[i] ) 81 { 82 L[R[i]] = L[i]; 83 R[L[i]] = R[i]; 84 } 85 } 86 87 void resume( int id ) 88 { 89 for ( int i = D[id]; i != id; i = D[i] ) 90 L[R[i]] = R[L[i]] = i; 91 } 92 93 int h() 94 { 95 int sum = 0; 96 memset( vis, 0, sizeof(vis) ); 97 for ( int i = R[0]; i != 0; i = R[i] ) 98 if (!vis[i]) 99 { 100 sum++; 101 for ( int j = D[i]; j != i; j = D[j] ) 102 for ( int k = R[j]; k != j; k = R[k] ) 103 vis[C[k]] = 1; 104 } 105 return sum; 106 } 107 108 void dance( int k ) 109 { 110 int mark, mmin = inf; 111 if ( k + h() >= fin ) 112 return; 113 if ( R[0] == 0 ) 114 { 115 if ( k < fin ) 116 fin = k; 117 return; 118 } 119 120 for ( int i = R[0]; i != 0; i = R[i] ) 121 if ( mmin > S[i] ) 122 { 123 mmin = S[i]; 124 mark = i; 125 } 126 127 for ( int i = D[mark]; i != mark; i = D[i] ) 128 { 129 remove(i); 130 for ( int j = R[i]; j != i; j = R[j] ) remove(j); 131 dance(k+1); 132 for ( int j = R[i]; j != i; j = R[j] ) resume(j); 133 resume(i); 134 } 135 } 136 }dlx; 137 138 int mmap[20][20], g[20][20]; 139 140 void init() 141 { 142 memset( mmap, 0, sizeof(mmap) ); 143 memset( g, 0, sizeof(g) ); 144 } 145 146 int main() 147 { 148 #ifdef local 149 freopen("F:\cpp\test.txt","r",stdin); 150 #endif 151 152 int R, C, r, c; 153 while ( ~scanf("%d %d", &R, &C) ) 154 { 155 init(); 156 int cnt = 0; 157 for ( int i = 1; i <= R; i++ ) 158 for (int j = 1; j <= C; j++) 159 { 160 scanf("%d", &mmap[i][j]); 161 if ( mmap[i][j] ) 162 g[i][j] = ++cnt; 163 } 164 scanf("%d %d", &r, &c); 165 dlx.init( (R-r+1)*(C-c+1), cnt ); 166 167 cnt = 1; 168 for ( int i = 1; i+r-1 <= R; i++ ) 169 for ( int j = 1; j+c-1 <= C; j++ ) 170 { 171 for ( int a = i; a <= i+r-1; a++ ) 172 for ( int b = j; b <= j + c - 1; b++ ) 173 if (g[a][b]) 174 dlx.link(cnt, g[a][b]); 175 cnt++; 176 } 177 dlx.dance(0); 178 printf("%d ", dlx.fin); 179 } 180 181 return 0; 182 }
5.POJ 3074
求解数独....emmmm我得好好理解下才行
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 #include <time.h> 12 13 #define SIGMA_SIZE 26 14 #define lson rt<<1 15 #define rson rt<<1|1 16 #pragma warning ( disable : 4996 ) 17 18 using namespace std; 19 typedef long long LL; 20 inline LL LMax(LL a,LL b) { return a>b?a:b; } 21 inline LL LMin(LL a,LL b) { return a>b?b:a; } 22 inline int Max(int a,int b) { return a>b?a:b; } 23 inline int Min(int a,int b) { return a>b?b:a; } 24 inline int gcd( int a, int b ) { return b==0?a:gcd(b,a%b); } 25 inline int lcm( int a, int b ) { return a/gcd(a,b)*b; } //a*b = gcd*lcm 26 const LL INF = 0x3f3f3f3f3f3f3f3f; 27 const LL mod = 1000000007; 28 const double eps = 1e-8; 29 const int inf = 0x3f3f3f3f; 30 const int maxk = 1e8; 31 const int maxn = 5000; 32 33 struct node { 34 int x, y, k; 35 }e[800]; 36 37 struct DLX { 38 int n, m, size, fin; 39 int U[maxn], D[maxn], L[maxn], R[maxn];//上下左右 40 int head[maxn], S[maxn]; //分别存每一行第一个1的点的标号和每一列1的个数 41 int row[maxn], col[maxn], ans[maxn]; //row,col表示第size个点在哪一行/列 42 43 44 void init( int _n, int _m ) 45 { 46 n = _n; m = _m; 47 for ( int i = 0; i <= m; i++ ) //初始化第一行(人为增加的虚拟行) 48 { 49 S[i] = 0; 50 U[i] = D[i] = i; 51 L[i] = i-1; 52 R[i] = i+1; 53 } 54 R[m] = 0; L[0] = m; //第一行的最后一个元素指向第一个 55 size = m; //从m开始以后都是普通节点 56 memset( head, -1, sizeof(head) ); 57 head[0] = 0; 58 } 59 60 void link( int r, int c ) 61 { 62 size++; //得到新的点标号 63 col[size] = c; //第size个点在第c列 64 row[size] = r; //第size个点在第r行 65 S[c]++; //第c列1的个数+1 66 67 //组成一个环,和下面左右一样的插法 68 D[size] = D[c]; 69 U[size] = c; 70 U[D[c]] = size; 71 D[c] = size; 72 73 //如果该行没有为1的节点 74 if ( head[r] < 0 ) head[r] = L[size] = R[size] = size; 75 else 76 { 77 //组成一个环,插在head[r]和head[r]右边那个元素中间 78 R[size] = R[head[r]]; 79 L[R[size]] = size; 80 L[size] = head[r]; 81 R[head[r]] = size; 82 } 83 } 84 85 void remove( int c ) //删除列c及其所在行 86 { 87 L[R[c]] = L[c]; R[L[c]] = R[c]; //c的左右两个节点互相连接 88 for ( int i = D[c]; i != c; i = D[i] ) //屏蔽c列 89 for ( int j = R[i]; j != i; j = R[j] ) 90 { 91 U[D[j]] = U[j]; 92 D[U[j]] = D[j]; 93 --S[col[j]]; //j所在的列的1的数目数减少 94 } 95 } 96 97 void resume( int c ) 98 { 99 for ( int i = U[c]; i != c; i = U[i] ) 100 for ( int j = L[i]; j != i; j = L[j] ) 101 { 102 U[D[j]] = D[U[j]] = j; 103 ++S[col[j]]; 104 } 105 L[R[c]] = R[L[c]] = c; 106 } 107 108 bool dance( int d ) 109 { 110 if ( R[0] == 0 ) //第0行没有节点 111 { 112 fin = d; 113 return true; 114 } 115 116 //找出含1数目最小的一列 117 int mark = R[0]; 118 for ( int i = R[0]; i != 0; i = R[i] ) 119 if ( S[i] < S[mark] ) 120 mark = i; 121 122 remove(mark); //移除列mark的1的对应行 123 for ( int i = D[mark]; i != mark; i = D[i] ) 124 { 125 ans[d] = row[i]; 126 //移除该行的1的对应列 127 for ( int j = R[i]; j != i; j = R[j] ) 128 remove(col[j]); 129 130 if ( dance(d+1) ) 131 return true; 132 133 //倒着恢复 134 for ( int j = L[i]; j != i; j = L[j] ) 135 resume(col[j]); 136 } 137 resume(mark); 138 return false; 139 } 140 }dlx; 141 142 143 int mmap[10][10]; 144 char sudoku[90]; 145 146 void read() 147 { 148 dlx.init(750,324); 149 int row = 0; 150 151 for ( int i = 1; i <= 9; i++ ) 152 for ( int j = 1; j <= 9; j++ ) 153 { 154 if ( !mmap[i][j] ) 155 { 156 for ( int k = 1; k <= 9; k++ ) 157 { 158 ++row; 159 dlx.link(row, (i-1)*9+j); 160 dlx.link(row, 81+(i-1)*9+k); 161 dlx.link(row, 162+(j-1)*9+k); 162 dlx.link(row,243+(((i-1)/3)*3+(j+2)/3-1)*9+k); 163 e[row].x = i; e[row].y = j; e[row].k = k; 164 } 165 } 166 else 167 { 168 ++row; 169 int k = mmap[i][j]; 170 dlx.link(row, (i-1)*9+j); 171 dlx.link(row, 81+(i-1)*9+k); 172 dlx.link(row, 162+(j-1)*9+k); 173 dlx.link(row, 243+(((i-1)/3)*3+(j+2)/3-1)*9+k); 174 e[row].x = i; e[row].y = j; e[row].k = k; 175 } 176 } 177 178 } 179 180 void init() 181 { 182 int t = 0; 183 184 for ( int i = 1; i <= 9; i++ ) 185 for ( int j = 1; j <= 9; j++ ) 186 { 187 if ( sudoku[++t] != '.' ) 188 mmap[i][j] = sudoku[t] - '0'; 189 else 190 mmap[i][j] = 0; 191 } 192 193 read(); 194 } 195 196 int main() 197 { 198 //freopen("F:\cpp\test.txt", "r", stdin ); 199 200 while ( ~scanf("%s", sudoku+1) ) 201 { 202 if (sudoku[1] == 'e') break; 203 init(); 204 205 dlx.dance(0); 206 for ( int i = 0; i < dlx.fin; i++ ) 207 { 208 int tmp = dlx.ans[i]; 209 sudoku[(e[tmp].x-1)*9 + e[tmp].y-1] = '0'+e[tmp].k; 210 } 211 sudoku[dlx.fin] = '