kuangbin带我飞QAQ DLX之一脸懵逼
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( "\n" ); 167 //continue; 168 } 169 else 170 printf("NO\n"); 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\n", 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\n", 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\n", (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\n", 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] = '\0'; 212 printf("%s\n", sudoku); 213 } 214 215 return 0; 216 }
6. HDU 5046
和hdu2295基本一样,有个可以优化的方法是将可行的距离排序后二分下标,如果不这样做直接二分,左右区间要到1~4e9才行,而且大概率TLE(交了一发1300ms)
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 = 5000; 31 const int maxn = 5000; 32 33 int N, K; 34 35 struct DLX { 36 int n, m, size, fin; 37 int U[maxk], D[maxk], L[maxk], R[maxk]; 38 int C[maxk]; 39 40 int head[65]; 41 int S[65]; 42 bool vis[maxk]; 43 44 void init( int _n, int _m ) 45 { 46 n = _n; m = _m; 47 for ( int i = 0; i <= m; i++ ) 48 { 49 U[i] = D[i] = i; 50 L[i] = i-1; 51 R[i] = i+1; 52 S[i] = 0; 53 } 54 L[0] = m; R[m] = 0; 55 size = m; 56 memset( head, -1, sizeof(head) ); 57 } 58 59 void link( int r, int c ) 60 { 61 size++; 62 C[size] = c; 63 S[c]++; 64 65 D[size] = D[c]; 66 U[size] = c; 67 U[D[c]] = size; 68 D[c] = size; 69 70 if ( head[r] < 0 ) 71 head[r] = L[size] = R[size] = size; 72 else 73 { 74 R[size] = R[head[r]]; 75 L[R[size]] = size; 76 L[size] = head[r]; 77 R[head[r]] = size; 78 } 79 } 80 81 void remove( int id ) 82 { 83 for ( int i = D[id]; i != id; i = D[i] ) 84 { 85 L[R[i]] = L[i]; 86 R[L[i]] = R[i]; 87 } 88 } 89 90 void resume( int id ) 91 { 92 for ( int i = D[id]; i != id; i = D[i] ) 93 L[R[i]] = R[L[i]] = i; 94 } 95 96 int h() 97 { 98 int sum = 0; 99 memset( vis, 0, sizeof(vis) ); 100 for ( int i = R[0]; i != 0; i = R[i] ) 101 if (!vis[i]) 102 { 103 sum++; 104 for ( int j = D[i]; j != i; j = D[j] ) 105 for ( int k = R[j]; k != j; k = R[k] ) 106 vis[C[k]] = 1; 107 } 108 return sum; 109 } 110 111 void dance( int k ) 112 { 113 int mark, mmin = inf; 114 int tmp = k + h(); 115 if ( tmp >= fin || tmp > K ) 116 return; 117 if ( R[0] == 0 ) 118 { 119 if ( k < fin ) 120 fin = k; 121 return; 122 } 123 124 for ( int i = R[0]; i != 0; i = R[i] ) 125 if ( mmin > S[i] ) 126 { 127 mmin = S[i]; 128 mark = i; 129 } 130 131 for ( int i = D[mark]; i != mark; i = D[i] ) 132 { 133 remove(i); 134 for ( int j = R[i]; j != i; j = R[j] ) remove(j); 135 dance(k+1); 136 for ( int j = R[i]; j != i; j = R[j] ) resume(j); 137 resume(i); 138 } 139 } 140 }dlx; 141 142 int cnt; 143 int g[62][2]; 144 145 struct mmap { 146 int x, y; 147 LL dist; 148 bool operator < ( const mmap &a ) const 149 { return dist < a.dist; } 150 }node[62*62]; 151 152 LL getdist( int i, int j ) 153 { 154 LL x = abs(g[i][0]-g[j][0]); 155 LL y = abs(g[i][1]-g[j][1]); 156 return x+y; 157 } 158 159 void init( int n ) 160 { 161 cnt = 0; 162 for( int i = 1; i <= n; i++ ) 163 scanf("%d %d", &g[i][0], &g[i][1] ); 164 for ( int i = 1; i <= n; i++ ) 165 for ( int j = i; j <= n; j++ ) 166 { 167 node[cnt].x = i; node[cnt].y = j; 168 node[cnt++].dist = getdist(i,j); 169 } 170 sort(node, node+cnt); 171 } 172 173 bool judge( int n, int k, LL mid ) 174 { 175 dlx.init(n, n); dlx.fin = k+1; 176 177 for ( int i = 0; i < cnt; i++ ) 178 { 179 if ( node[i].dist > mid ) break; 180 181 dlx.link( node[i].x, node[i].y ); 182 if ( node[i].x != node[i].y ) 183 dlx.link( node[i].y, node[i].x ); 184 } 185 186 dlx.dance(0); 187 if ( dlx.fin <= k ) 188 return true; 189 else 190 return false; 191 } 192 193 LL solve( int n, int k ) 194 { 195 LL mid, lhs = 0, rhs = cnt; 196 while ( lhs <= rhs ) 197 { 198 mid = (lhs+rhs)>>1; 199 if ( judge(n,k,node[mid].dist) ) 200 rhs = mid-1; 201 else 202 lhs = mid+1; 203 } 204 205 if ( judge(n,k,node[lhs].dist) ) 206 return node[lhs].dist; 207 else 208 return node[rhs].dist; 209 } 210 211 int main() 212 { 213 //freopen("F:\\cpp\\test.txt", "r", stdin ); 214 215 int T; cin >> T; 216 int n, k, cnt = 1; 217 while (T--) 218 { 219 scanf("%d %d", &n, &k); 220 N = n; K = k; 221 init(n); 222 printf("Case #%d: %lld\n", cnt++, solve(n,k)); 223 } 224 225 return 0; 226 }
7.ZOJ 3122
16个数字的数独,和9个数字的数独其实一样,这次加了注释,终于理解了...然后dlx范围老是调不好
1 #include <iostream> 2 #include <string.h> 3 #include <cstdio> 4 #include <vector> 5 #include <string> 6 #include <algorithm> 7 #include <math.h> 8 #include <time.h> 9 10 #define SIGMA_SIZE 26 11 #define lson rt<<1 12 #define rson rt<<1|1 13 #pragma warning ( disable : 4996 ) 14 15 using namespace std; 16 typedef long long LL; 17 inline LL LMax(LL a,LL b) { return a>b?a:b; } 18 inline LL LMin(LL a,LL b) { return a>b?b:a; } 19 inline int Max(int a,int b) { return a>b?a:b; } 20 inline int Min(int a,int b) { return a>b?b:a; } 21 inline int gcd( int a, int b ) { return b==0?a:gcd(b,a%b); } 22 inline int lcm( int a, int b ) { return a/gcd(a,b)*b; } //a*b = gcd*lcm 23 const LL INF = 0x3f3f3f3f3f3f3f3f; 24 const LL mod = 1000000007; 25 const double eps = 1e-8; 26 const int inf = 0x3f3f3f3f; 27 const int maxk = 1e5; 28 const int maxn = 1030; 29 30 //行:16x16x16=4096表示每个格子有16种选择 31 //列:(16x16)x3=768,表示16行16列16小块每个各有16种数字单独存在 32 //列:还要加上768+16x16=1024,表示每个格子只能有一个数字 33 34 struct DLX { 35 int n, m, size, fin; 36 int U[maxk], D[maxk], L[maxk], R[maxk];//上下左右 37 int head[maxk], S[maxk]; //分别存每一行第一个1的点的标号和每一列1的个数 38 int row[maxk], col[maxk], ans[maxk]; //row,col表示第size个点在哪一行/列 39 40 41 void init( int _n, int _m ) 42 { 43 n = _n; m = _m; 44 for ( int i = 0; i <= m; i++ ) //初始化第一行(人为增加的虚拟行) 45 { 46 S[i] = 0; 47 U[i] = D[i] = i; 48 L[i] = i-1; 49 R[i] = i+1; 50 } 51 R[m] = 0; L[0] = m; //第一行的最后一个元素指向第一个 52 size = m; //从m开始以后都是普通节点 53 memset( head, -1, sizeof(head) ); 54 head[0] = 0; 55 } 56 57 void link( int r, int c ) 58 { 59 size++; //得到新的点标号 60 col[size] = c; //第size个点在第c列 61 row[size] = r; //第size个点在第r行 62 S[c]++; //第c列1的个数+1 63 64 //组成一个环,和下面左右一样的插法 65 D[size] = D[c]; 66 U[size] = c; 67 U[D[c]] = size; 68 D[c] = size; 69 70 //如果该行没有为1的节点 71 if ( head[r] < 0 ) head[r] = L[size] = R[size] = size; 72 else 73 { 74 //组成一个环,插在head[r]和head[r]右边那个元素中间 75 R[size] = R[head[r]]; 76 L[R[size]] = size; 77 L[size] = head[r]; 78 R[head[r]] = size; 79 } 80 } 81 82 void remove( int c ) //删除列c及其所在行 83 { 84 L[R[c]] = L[c]; R[L[c]] = R[c]; //c的左右两个节点互相连接 85 for ( int i = D[c]; i != c; i = D[i] ) //屏蔽c列 86 for ( int j = R[i]; j != i; j = R[j] ) 87 { 88 U[D[j]] = U[j]; 89 D[U[j]] = D[j]; 90 --S[col[j]]; //j所在的列的1的数目数减少 91 } 92 } 93 94 void resume( int c ) 95 { 96 for ( int i = U[c]; i != c; i = U[i] ) 97 for ( int j = L[i]; j != i; j = L[j] ) 98 { 99 U[D[j]] = D[U[j]] = j; 100 ++S[col[j]]; 101 } 102 L[R[c]] = R[L[c]] = c; 103 } 104 105 bool dance( int d ) 106 { 107 if ( R[0] == 0 ) //第0行没有节点 108 { 109 fin = d; 110 return true; 111 } 112 113 //找出含1数目最小的一列 114 int mark = R[0]; 115 for ( int i = R[0]; i != 0; i = R[i] ) 116 if ( S[i] < S[mark] ) 117 mark = i; 118 119 remove(mark); //移除列mark的1的对应行 120 for ( int i = D[mark]; i != mark; i = D[i] ) 121 { 122 ans[d] = row[i]; 123 //移除该行的1的对应列 124 for ( int j = R[i]; j != i; j = R[j] ) 125 remove(col[j]); 126 127 if ( dance(d+1) ) 128 return true; 129 130 //倒着恢复 131 for ( int j = L[i]; j != i; j = L[j] ) 132 resume(col[j]); 133 } 134 resume(mark); 135 return false; 136 } 137 }dlx; 138 139 char mmap[20][20]; 140 char sudoku[20][20]; 141 struct node { 142 int x, y, k; 143 }e[maxk]; 144 145 146 void init() 147 { 148 //4096行,1024列 149 dlx.init(4096,1024); 150 int row = 0; 151 152 for ( int i = 1; i <= 16; i++ ) 153 for ( int j = 1; j <= 16; j++ ) 154 { 155 if ( mmap[i][j] == '-' ) 156 for (int k = 1; k <= 16; k++ ) 157 { 158 row++; 159 dlx.link(row, (i-1)*16+j ); //第i行第j个格子已经填了数字 160 dlx.link(row, 256+(i-1)*16+k); //第i行已经填了数字k 161 dlx.link(row, 512+(j-1)*16+k); //第j列已经填了数字k 162 dlx.link(row, 768+(((i-1)/4)*4 + (j-1)/4)*16+k); //第xxx个格子已经填了数字k 163 e[row].x = i; e[row].y = j; e[row].k = k; 164 } 165 else 166 { 167 row++; 168 int k = mmap[i][j] - 'A' + 1; 169 dlx.link(row, (i-1)*16+j); 170 dlx.link(row, 256+(i-1)*16+k); 171 dlx.link(row, 512+(j-1)*16+k); 172 dlx.link(row, 768+(((i-1)/4)*4 + (j-1)/4)*16+k); 173 e[row].x = i; e[row].y = j; e[row].k = k; 174 } 175 } 176 } 177 178 int main() 179 { 180 //freopen("F:\\cpp\\test.txt", "r", stdin ); 181 182 int cnt = 0; 183 while (1) 184 { 185 if ( ~scanf("%s", mmap[1]+1) ) 186 { 187 for ( int i = 2; i <= 16; i++ ) 188 scanf("%s", mmap[i]+1); 189 190 if (cnt++) 191 printf("\n"); 192 193 init(); 194 dlx.dance(0); 195 196 int tmp; 197 for ( int i = 0; i < dlx.fin; i++ ) 198 { 199 tmp = dlx.ans[i]; 200 sudoku[e[tmp].x-1][e[tmp].y-1] = e[tmp].k + 'A' - 1; 201 sudoku[e[tmp].x-1][16] = '\0'; 202 } 203 for ( int i = 0; i < 16; i++ ) 204 printf("%s\n", sudoku[i]); 205 } 206 else 207 break; 208 } 209 }
什么时候能够不再这么懒惰