两道入门题
HihoCoder1317
精确覆盖问题:在一个0-1矩阵中,选定部分行,使得每一列都有且只有一个1。求解一种选法。
当然使用搜索来解决,先选择一行,然后将不能选的行给删掉,然后再继续向下,完成后恢复现场。(X算法)
但是这样的方法,在对于矩阵的删除行列和恢复操作太复杂,所以使用一种数据结构--舞蹈链(Dance Link),也就是一个循环十字链表,可以快速的删掉和恢复某行某列。
结合了舞蹈链的搜索就称作DLX算法。
题目链接中有了很不错的分析。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int maxn = 200;
const int maxr = 200;
const int maxnode = 1e6;
struct DLX
{
int U[maxnode], D[maxnode], L[maxnode], R[maxnode];
int row[maxnode], col[maxnode];
int S[maxn], H[maxr], ans[maxr], ansd, sz;
int n,m;
void init(int n, int m){
this->n = n; this->m = m;
for(int i = 0; i <= m; i++){
L[i] = i-1; R[i] = i+1; U[i] = D[i] = i;
}
L[0] = m; R[m] = 0; sz = m+1;
memset(S, 0, sizeof(S));
memset(H, -1, sizeof(H));
}
void addNode(int r, int c){
row[sz] = r; col[sz] = c;
U[sz] = U[c]; D[sz] = c;
D[U[sz]] = sz; U[D[sz]] = sz;
if(H[r] == -1){
L[sz] = sz; R[sz] = sz;
H[r] = sz;
}else{
R[sz] = H[r]; L[sz] = L[H[r]];
L[R[sz]] = sz; R[L[sz]] = sz;
}
S[col[sz]]++; sz++;
}
#define FOR(i, A, s) for(int i = A[s]; i != s; i = A[i])
void remove(int c){
R[L[c]] = R[c]; L[R[c]] = L[c];
FOR(i, D, c) FOR(j, R, i){
U[D[j]] = U[j]; D[U[j]] = D[j]; S[col[j]]--;
}
}
void restore(int c){
FOR(i, U, c) FOR(j, L, i){
U[D[j]] = j; D[U[j]] = j; S[col[j]]++;
}
R[L[c]] = c; L[R[c]] = c;
}
bool dfs(int d){
if(R[0] == 0){
ansd = d;
return true;
}
int c = R[0];
FOR(i, R, 0){
if(S[i] < S[c]) c = i;
}
remove(c);
FOR(i, D, c){
ans[d] = row[i];
FOR(j, R, i) remove(col[j]);
if(dfs(d+1)) return true;
FOR(j, L, i) restore(col[j]);
}
restore(c);
return false;
}
}dlx;
int t,n,m;
int main()
{
cin >> t;
while(t--){
cin >> n >> m;
dlx.init(n,m);
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
int tmp;
cin >> tmp;
if(tmp) dlx.addNode(i,j);
}
}
if(dlx.dfs(0)){
cout << "Yes
";
}else{
cout << "No
";
}
}
return 0;
}
HihoCoder1321
解数独问题:
可以转变成精确覆盖问题来解决。
每一行代表这一项决策,共有9*9*9
行,i*9*9+j*9+k
表示第i行j列的格子里面填k这项决策
每一列表示一个任务,共有4*9*9
列
有四类任务:
- SLOT(i,j) 第i行j列要放当前的决策值
- ROW(i,k) 第i行要有k值
- COL(j,k) 第j列要有k值
- SUB(s,k) 第s个九宫要有k值
#include <cstdio>
#include <cstring>
#include <vector>
#include <iostream>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int maxn = 1020;
const int maxr = 1020;
const int maxnode = 2e6;
struct DLX
{
int U[maxnode], D[maxnode], L[maxnode], R[maxnode];
int row[maxnode], col[maxnode];
int S[maxn], H[maxr], ans[maxr], ansd, sz;
int n,m;
void init(int n, int m){
this->n = n; this->m = m;
for(int i = 0; i <= m; i++){
L[i] = i-1; R[i] = i+1; U[i] = D[i] = i;
}
L[0] = m; R[m] = 0; sz = m+1;
memset(S, 0, sizeof(S));
memset(H, -1, sizeof(H));
}
void addNode(int r, int c){
row[sz] = r; col[sz] = c;
U[sz] = U[c]; D[sz] = c;
D[U[sz]] = sz; U[D[sz]] = sz;
if(H[r] == -1){
L[sz] = sz; R[sz] = sz;
H[r] = sz;
}else{
R[sz] = H[r]; L[sz] = L[H[r]];
L[R[sz]] = sz; R[L[sz]] = sz;
}
S[col[sz]]++; sz++;
}
#define FOR(i, A, s) for(int i = A[s]; i != s; i = A[i])
void remove(int c){
R[L[c]] = R[c]; L[R[c]] = L[c];
FOR(i, D, c) FOR(j, R, i){
U[D[j]] = U[j]; D[U[j]] = D[j]; S[col[j]]--;
}
}
void restore(int c){
FOR(i, U, c) FOR(j, L, i){
U[D[j]] = j; D[U[j]] = j; S[col[j]]++;
}
R[L[c]] = c; L[R[c]] = c;
}
bool dfs(int d){
if(R[0] == 0){
ansd = d;
return true;
}
int c = R[0];
FOR(i, R, 0){
if(S[i] < S[c]) c = i;
}
remove(c);
FOR(i, D, c){
ans[d] = row[i];
FOR(j, R, i) remove(col[j]);
if(dfs(d+1)) return true;
FOR(j, L, i) restore(col[j]);
}
restore(c);
return false;
}
bool solve(vector<int> &v){
v.clear();
if(!dfs(0)) return false;
for(int i = 0; i < ansd; i++){
v.push_back(ans[i]);
}
return true;
}
}dlx;
int t,n,m;
int cnt_r, cnt_c;
int mp[10][10];
int encode(int x, int y, int z){
return x*81+y*9+z+1;
}
void decode(int code, int &x, int &y, int &z){
code--;
z = code%9; code /= 9;
y = code%9; code /= 9;
x = code%9;
}
const int SLOT = 0;
const int ROW = 1;
const int COL = 2;
const int SUB = 3;
int main()
{
cin >> t;
cnt_r = 9*9*9; cnt_c = 9*9*4;
while(t--){
dlx.init(cnt_r, cnt_c);
for(int i = 0; i < 9; i++){
for(int j = 0; j < 9; j++){
cin >> mp[i][j];
}
}
for(int i = 0; i < 9; i++){
for(int j = 0; j < 9; j++){
for(int k = 0; k < 9; k++){
if(mp[i][j] == 0 || mp[i][j] == k+1){
int r = encode(i, j, k);
dlx.addNode(r, encode(SLOT, i, j));
dlx.addNode(r, encode(ROW, i, k));
dlx.addNode(r, encode(COL, j, k));
dlx.addNode(r, encode(SUB, (i/3)*3+j/3, k));// 6,9
}
}
}
}
vector<int> v;
dlx.solve(v);
for(int i = 0; i < v.size(); i++){
int r, c, k;
decode(v[i], r, c, k);
mp[r][c] = k+1;
}
for(int i = 0; i < 9; i++){
for(int j = 0; j < 9; j++){
if(j) cout << ' ';
cout << mp[i][j];
}
cout << "
";
}
}
return 0;
}