[csu1605]数独(精确覆盖问题)

题意 :给定数独的某些初始值,规定每个格子的得分,求得分最大的数独的解。

思路:这是某年的noip的原题,高中时就写过,位运算也就是那个时候学会的--。这题明显是暴搜,但是需要注意两点,一是需要加一些常数优化,也就是位运算,一个是剪枝,填完某个数后发现某个格子无解了则换个数填,并且那些可填的数的种数少的格子尽量先填,因为这样尽可能让矛盾在靠近根的地方出现。今天粗略学了一下舞蹈链--DLX,这个算法(准确来说是一个结构)可以比较高效的解决一些精确覆盖问题,对于重复覆盖问题稍作修改也适用。用DLX写了一遍数独,发现效率比位运算略高一点,但不明显。

位运算:

  1 #pragma comment(linker, "/STACK:10240000,10240000")
  2
  3 #include <iostream>
  4 #include <cstdio>
  5 #include <algorithm>
  6 #include <cstdlib>
  7 #include <cstring>
  8 #include <map>
  9 #include <queue>
 10 #include <deque>
 11 #include <cmath>
 12 #include <vector>
 13 #include <ctime>
 14 #include <cctype>
 15 #include <set>
 16 #include <bitset>
 17 #include <functional>
 18 #include <numeric>
 19 #include <stdexcept>
 20 #include <utility>
 21
 22 using namespace std;
 23
 24 #define mem0(a) memset(a, 0, sizeof(a))
 25 #define mem_1(a) memset(a, -1, sizeof(a))
 26 #define lson l, m, rt << 1
 27 #define rson m + 1, r, rt << 1 | 1
 28 #define define_m int m = (l + r) >> 1
 29 #define rep_up0(a, b) for (int a = 0; a < (b); a++)
 30 #define rep_up1(a, b) for (int a = 1; a <= (b); a++)
 31 #define rep_down0(a, b) for (int a = b - 1; a >= 0; a--)
 32 #define rep_down1(a, b) for (int a = b; a > 0; a--)
 33 #define all(a) (a).begin(), (a).end()
 34 #define lowbit(x) ((x) & (-(x)))
 35 #define constructInt4(name, a, b, c, d) name(int a = 0, int b = 0, int c = 0, int d = 0): a(a), b(b), c(c), d(d) {}
 36 #define constructInt3(name, a, b, c) name(int a = 0, int b = 0, int c = 0): a(a), b(b), c(c) {}
 37 #define constructInt2(name, a, b) name(int a = 0, int b = 0): a(a), b(b) {}
 38 #define pchr(a) putchar(a)
 39 #define pstr(a) printf("%s", a)
 40 #define sstr(a) scanf("%s", a)
 41 #define sint(a) scanf("%d", &a)
 42 #define sint2(a, b) scanf("%d%d", &a, &b)
 43 #define sint3(a, b, c) scanf("%d%d%d", &a, &b, &c)
 44 #define pint(a) printf("%d\n", a)
 45 #define test_print1(a) cout << "var1 = " << a << endl
 46 #define test_print2(a, b) cout << "var1 = " << a << ", var2 = " << b << endl
 47 #define test_print3(a, b, c) cout << "var1 = " << a << ", var2 = " << b << ", var3 = " << c << endl
 48
 49 typedef long long LL;
 50 typedef pair<int, int> pii;
 51 typedef vector<int> vi;
 52
 53 const int dx[8] = {0, 0, -1, 1, 1, 1, -1, -1};
 54 const int dy[8] = {-1, 1, 0, 0, 1, -1, 1, -1 };
 55 const int maxn = 3e4 + 7;
 56 const int md = 10007;
 57 const int inf = 1e9 + 7;
 58 const LL inf_L = 1e18 + 7;
 59 const double pi = acos(-1.0);
 60 const double eps = 1e-6;
 61
 62 template<class T>T gcd(T a, T b){return b==0?a:gcd(b,a%b);}
 63 template<class T>bool max_update(T &a,const T &b){if(b>a){a = b; return true;}return false;}
 64 template<class T>bool min_update(T &a,const T &b){if(b<a){a = b; return true;}return false;}
 65 template<class T>T condition(bool f, T a, T b){return f?a:b;}
 66 template<class T>void copy_arr(T a[], T b[], int n){rep_up0(i,n)a[i]=b[i];}
 67 int make_id(int x, int y, int n) { return x * n + y; }
 68
 69 int ans, a[10][10], f[1 << 13], row[10], col[10], block[10], sp[1 << 13];
 70
 71 int getScore(int i, int j) {
 72     return min(min(i, 8 - i), min(j, 8 - j)) + 6;
 73 }
 74
 75 void init() {
 76     rep_up0(i, 12) {
 77         f[1 << i] = i;
 78     }
 79 }
 80
 81 void dfs(int k, int score) {
 82     if (k >= 81) {
 83         max_update(ans, score);
 84         return ;
 85     }
 86     int x, y, c = 10;
 87     rep_up0(i, 9) {
 88         bool ok = false;
 89         rep_up0(j, 9) {
 90             if (a[i][j]) continue;
 91             int tmp = row[i] | col[j] | block[make_id(i / 3, j / 3, 3)];
 92             int tot = 0x3fe ^ tmp;
 93             int cnt = 0;
 94             if (tot == 0) {
 95                 ok = true;
 96                 c = 0;
 97                 break;
 98             }
 99             cnt = sp[tot];
100             if (cnt < c) {
101                 x = i;
102                 y = j;
103                 c = cnt;
104             }
105         }
106         if (ok) break;
107     }
108     if (c == 0 || c == 10) return ;
109     int i = x, j = y;
110     int tmp = row[i] | col[j] | block[make_id(i / 3, j / 3, 3)];
111     int tot = 0x3fe ^ tmp;
112     while (tot) {
113         tmp = lowbit(tot);
114         row[i] ^= 1 << f[tmp];
115         col[j] ^= 1 << f[tmp];
116         block[make_id(i / 3, j / 3, 3)] ^= 1 << f[tmp];
117         a[i][j] = f[tmp];
118         dfs(k + 1, score + f[tmp] * getScore(i, j));
119         row[i] ^= 1 << f[tmp];
120         col[j] ^= 1 << f[tmp];
121         block[make_id(i / 3, j / 3, 3)] ^= 1 << f[tmp];
122         a[i][j] = 0;
123         tot -= tmp;
124     }
125 }
126
127 int main() {
128     //freopen("in.txt", "r", stdin);
129     sp[0] = 0;
130     rep_up1(i, 1 << 10) {
131         sp[i] = sp[i - lowbit(i)] + 1;
132     }
133     int T;
134     init();
135     cin >> T;
136     while (T --) {
137         int sum = 0, cnt = 0, ok = true;
138         mem0(col);
139         mem0(row);
140         mem0(block);
141         rep_up0(i, 9) {
142             rep_up0(j, 9) {
143                 sint(a[i][j]);
144                 sum += a[i][j] * getScore(i, j);
145                 if (a[i][j]) {
146                     cnt ++;
147                     if (col[j] & (1 << a[i][j])) ok = false;
148                     if (row[i] & (1 << a[i][j])) ok = false;
149                     if (block[make_id(i / 3, j / 3, 3)] & (1 << a[i][j])) ok = false;
150                     col[j] |= 1 << a[i][j];
151                     row[i] |= 1 << a[i][j];
152                     block[make_id(i / 3, j / 3, 3)] |= 1 << a[i][j];
153                 }
154             }
155         }
156         ans = -1;
157         if (ok) dfs(cnt, sum);
158         cout << ans << endl;
159     }
160 }

DLX(模板):

  1 #pragma comment(linker, "/STACK:102400000,102400000")
  2
  3 #include <iostream>
  4 #include <cstdio>
  5 #include <algorithm>
  6 #include <cstdlib>
  7 #include <cstring>
  8 #include <map>
  9 #include <queue>
 10 #include <deque>
 11 #include <cmath>
 12 #include <vector>
 13 #include <ctime>
 14 #include <cctype>
 15 #include <set>
 16 #include <bitset>
 17 #include <functional>
 18 #include <numeric>
 19 #include <stdexcept>
 20 #include <utility>
 21
 22 using namespace std;
 23
 24 #define mem0(a) memset(a, 0, sizeof(a))
 25 #define mem_1(a) memset(a, -1, sizeof(a))
 26 #define lson l, m, rt << 1
 27 #define rson m + 1, r, rt << 1 | 1
 28 #define define_m int m = (l + r) >> 1
 29 #define rep_up0(a, b) for (int a = 0; a < (b); a++)
 30 #define rep_up1(a, b) for (int a = 1; a <= (b); a++)
 31 #define rep_down0(a, b) for (int a = b - 1; a >= 0; a--)
 32 #define rep_down1(a, b) for (int a = b; a > 0; a--)
 33 #define all(a) (a).begin(), (a).end()
 34 #define lowbit(x) ((x) & (-(x)))
 35 #define constructInt4(name, a, b, c, d) name(int a = 0, int b = 0, int c = 0, int d = 0): a(a), b(b), c(c), d(d) {}
 36 #define constructInt3(name, a, b, c) name(int a = 0, int b = 0, int c = 0): a(a), b(b), c(c) {}
 37 #define constructInt2(name, a, b) name(int a = 0, int b = 0): a(a), b(b) {}
 38 #define pchr(a) putchar(a)
 39 #define pstr(a) printf("%s", a)
 40 #define sstr(a) scanf("%s", a)
 41 #define sint(a) scanf("%d", &a)
 42 #define sint2(a, b) scanf("%d%d", &a, &b)
 43 #define sint3(a, b, c) scanf("%d%d%d", &a, &b, &c)
 44 #define pint(a) printf("%d\n", a)
 45 #define test_print1(a) cout << "var1 = " << a << endl
 46 #define test_print2(a, b) cout << "var1 = " << a << ", var2 = " << b << endl
 47 #define test_print3(a, b, c) cout << "var1 = " << a << ", var2 = " << b << ", var3 = " << c << endl
 48
 49 typedef long long LL;
 50 typedef pair<int, int> pii;
 51 typedef vector<int> vi;
 52
 53 const int dx[8] = {0, 0, -1, 1, 1, 1, -1, -1};
 54 const int dy[8] = {-1, 1, 0, 0, 1, -1, 1, -1 };
 55 const int maxn = 1e5 + 7;
 56 const int md = 10007;
 57 const int inf = 1e9 + 7;
 58 const LL inf_L = 1e18 + 7;
 59 const double pi = acos(-1.0);
 60 const double eps = 1e-6;
 61
 62 template<class T>T gcd(T a, T b){return b==0?a:gcd(b,a%b);}
 63 template<class T>bool max_update(T &a,const T &b){if(b>a){a = b; return true;}return false;}
 64 template<class T>bool min_update(T &a,const T &b){if(b<a){a = b; return true;}return false;}
 65 template<class T>T condition(bool f, T a, T b){return f?a:b;}
 66 template<class T>void copy_arr(T a[], T b[], int n){rep_up0(i,n)a[i]=b[i];}
 67 int make_id(int x, int y, int n) { return x * n + y; }
 68
 69 ///行编号从1开始,列编号1~n,结点0是表头结点,结点1~n是各列顶部的虚拟结点
 70 int result;
 71 int b[10][10];
 72
 73 int encode(int a, int b, int c) {
 74     return a * 81 + b * 9 + c + 1;
 75 }
 76 void decode(int code, int &a, int &b, int &c) {
 77     code --;
 78     c = code % 9; code /= 9;
 79     b = code % 9; code /= 9;
 80     a = code;
 81 }
 82
 83 struct DLX
 84 {
 85     const static int maxn = 1050;
 86     const static int maxnode = 100007;
 87     int n , sz;                                                 // 行数,节点总数
 88     int S[maxn];                                                // 各列节点总数
 89     int row[maxnode],col[maxnode];                              // 各节点行列编号
 90     int L[maxnode],R[maxnode],U[maxnode],D[maxnode];            // 十字链表
 91
 92     int ansd,ans[maxn];                                         // 解
 93
 94     void init(int n )
 95     {
 96         this->n = n ;
 97         for(int i = 0 ; i <= n; i++ )
 98             {
 99               U[i] = i ;
100               D[i] = i ;
101               L[i] = i - 1;
102               R[i] = i + 1;
103         }
104         R[n] = 0 ;
105         L[0] = n;
106         sz = n + 1 ;
107         memset(S,0,sizeof(S));
108     }
109     void addRow(int r,vector<int> c1)
110     {
111         int first = sz;
112         for(int i = 0 ; i < c1.size(); i++ ){
113             int c = c1[i];
114             L[sz] = sz - 1 ; R[sz] = sz + 1 ; D[sz] = c ; U[sz] = U[c];
115             D[U[c]] = sz; U[c] = sz;
116             row[sz] = r; col[sz] = c;
117             S[c] ++ ; sz ++ ;
118         }
119         R[sz - 1] = first ; L[first] = sz - 1;
120     }
121     // 顺着链表A,遍历除s外的其他元素
122     #define FOR(i,A,s) for(int i = A[s]; i != s ; i = A[i])
123
124     void remove(int c) {
125         L[R[c]] = L[c];
126         R[L[c]] = R[c];
127         FOR(i,D,c)
128             FOR(j,R,i) {U[D[j]] = U[j];D[U[j]] = D[j];--S[col[j]];}
129     }
130     void restore(int c) {
131         FOR(i,U,c)
132             FOR(j,L,i) {++S[col[j]];U[D[j]] = j;D[U[j]] = j; }
133         L[R[c]] = c;
134         R[L[c]] = c;
135     }
136     void update() {
137         int score = 0;
138         rep_up0(i, ansd) {
139             int r, c, v;
140             decode(ans[i], r, c, v);
141             score += (v + 1) * b[r][c];
142         }
143         max_update(result, score);
144     }
145     bool dfs(int d) {
146         if(R[0] == 0) {
147           ansd = d;
148           update();
149           return true;
150         }
151         // 找S最小的列c
152         int c = R[0];
153         FOR(i,R,0) if(S[i] < S[c]) c = i;
154
155         remove(c);
156         FOR(i,D,c) {
157             ans[d] = row[i];
158             FOR(j,R,i) remove(col[j]);
159             //if(dfs(d + 1)) return true;
160             dfs(d + 1);
161             FOR(j,L,i) restore(col[j]);
162         }
163         restore(c);
164
165         //return false;
166     }
167     bool solve(vector<int> & v) {
168         v.clear();
169         if(!dfs(0)) return false;
170         for(int i = 0 ; i < ansd ;i ++) v.push_back(ans[i]);
171         return true;
172     }
173 };
174
175 DLX solver;
176 int a[12][12];
177
178
179 int main() {
180     //freopen("in.txt", "r", stdin);
181     rep_up0(i, 9) {
182         rep_up0(j, 9) {
183             b[i][j] = 6 + min(min(i, 8 - i), min(j, 8 - j));
184         }
185     }
186     int T, x;
187     cin >> T;
188     while (T --) {
189         solver.init(324);
190         rep_up0(i, 9) {
191             rep_up0(j, 9) {
192                 int x;
193                 sint(x);
194                 rep_up0(k, 9) {
195                     if (x == 0 || x == k + 1) {
196                         vector<int> col;
197                         col.push_back(encode(0, i, j));
198                         col.push_back(encode(1, i, k));
199                         col.push_back(encode(2, j, k));
200                         col.push_back(encode(3, make_id(i / 3, j / 3, 3), k));
201                         solver.addRow(encode(i, j, k), col);
202                     }
203                 }
204             }
205         }
206         result = -1;
207         solver.dfs(0);
208         cout << result << endl;
209     }
210     return 0;
211 }

时间: 2024-11-05 06:42:42

[csu1605]数独(精确覆盖问题)的相关文章

hihoCoder #1321 : 搜索五?数独 (Dancing Links ,精确覆盖)

hiho一下第102周的题目. 原题地址:http://hihocoder.com/problemset/problem/1321 题意:输入一个9*9数独矩阵,0表示没填的空位,输出这个数独的答案. 提示已经讲解的很清楚了.稍微整理下思路.最后附AC代码. 一.Dancing Links解决精确覆盖问题.      1.精确覆盖问题         给定一个n行,m列的01矩阵.从中选择若干行使得每一列有且恰好只有一个1. 例如: 答案是选择2,3,4行. 2.DancingLinks求解精确

hdu 1426 Sudoku Killer ( Dancing Link 精确覆盖 )

利用 Dancing Link 来解数独 具体的可以看    lrj 的训练指南 和 < Dancing Links 在搜索中的应用 >这篇论文 Dancing Link 来求解数独 , 是通过求解精确覆盖 精确覆盖就是给出一个 01 矩阵 , 要求我们选择一些行 , 使得每一列有且仅有一个 1 对于数独问题 , 行就是我们的选择 , 即在第 i 行 第 j 列 放上 数字 k , 所以我们最多有 i * j * k 中选择 如果某些位置( x , y  )已经放了数字 a , 那么我们的选择

HDU 3111 Sudoku(精确覆盖)

数独问题,输入谜题,输出解 既然都把重复覆盖的给写成模板了,就顺便把精确覆盖的模板也写好看点吧...赤裸裸的精确覆盖啊~~~水一水~~~然后继续去搞有点难度的题了... 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <cmath> 6 #include <string> 7 #includ

(简单) POJ 3074 Sudoku, DLX+精确覆盖。

Description In the game of Sudoku, you are given a large 9 × 9 grid divided into smaller 3 × 3 subgrids. For example, . 2 7 3 8 . . 1 . . 1 . . . 6 7 3 5 . . . . . . . 2 9 3 . 5 6 9 2 . 8 . . . . . . . . . . . 6 . 1 7 4 5 . 3 6 4 . . . . . . . 9 5 1

poj3074 DLX精确覆盖

题意:解数独 分析: 完整的数独有四个充要条件: 1.每个格子都有填数字 2.每列都有1~9中的每个数字 3.每行都有1~9中的每个数字 4.每个9宫格都有1~9中的每个数字 可以转化成精确覆盖问题.每行表示一个格子的一种填法,1~81列表示这个格子的位置,82~162列表示这是哪一行的什么数字,163~243列表示这是哪一列的什么数字,244~324列表示这是哪一个九宫格里的什么数字.每行都把四个1填入这四个区间里的对应位置.最后求出这个01矩阵的精确覆盖就是解. 对于已经确定的点 我们就直接

LeetCode----Sudoku Solver+精确覆盖问题解法(Dancing Links)

BackGround: 做完LeetCode上的数独题目好长时间了,今天将做题时参考的Algorithm X 以及 Dancing Links 整理出来.话说理解算法+写出程序一共用了三天,智商果然余额不足... 介绍: 由于Dancing Links 是为了解决数独问题学习的,那就从数独问题下手,围绕数独问题展开对Algorithm X 和 Dancing Links的介绍,最后将数独问题的解法以及Java源码放出来. 精确覆盖问题: 没错,解数独的问题就是一个解  精确覆盖   问题的过程,

POJ 3047 Sudoku DLX精确覆盖

DLX精确覆盖.....模版题 Sudoku Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8336   Accepted: 2945 Description In the game of Sudoku, you are given a large 9 × 9 grid divided into smaller 3 × 3 subgrids. For example, . 2 7 3 8 . . 1 . . 1 . .

hust 1017 dancing links 精确覆盖模板题

最基础的dancing links的精确覆盖题目 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 6 using namespace std; 7 #define N 1005 8 #define MAXN 1000100 9 10 struct DLX{ 11 int n , m , size;//size表示当前dlx表中有多少

ZOJ 3209 Treasure Map(DLX精确覆盖)

Your boss once had got many copies of a treasure map. Unfortunately, all the copies are now broken to many rectangular pieces, and what make it worse, he has lost some of the pieces. Luckily, it is possible to figure out the position of each piece in