AlgorithmX精确覆盖:

https://en.wikipedia.org/wiki/Knuth's_Algorithm_X

DLX的基础算法

https://zh.wikipedia.org/wiki/舞蹈链

论文:

https://arxiv.org/pdf/cs/0011047v1.pdf

中文版:

http://io.sqybi.com/dlxcn/#p11

精确覆盖的思想是选取n行中的x行,以至于m列都恰好一个1,可以求出所有解,也可以根据需要求最优解

为什么这玩意能解决精确覆盖呢,比如有nm的矩形让你用k个小矩形恰好覆盖,不相互覆盖

这里由于algorithmX解决的是所有列都恰好覆盖,好像不对啊,所以可以把n
m的矩形拉成一条直线,每个格子都是一列,这样就可以恰好覆盖所有列,也就是恰好覆盖n*m的矩形了

然后这里每行对应的列,就是原来每个小矩形对应的列,映射一下,构图,然后就可以用DLX解决了

#include <cstdio>
#include <memory>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <vector>
#include <cassert>
#include <string>
#include <ctime>
#include <map>
#include <queue>
#include <algorithm>
#include <iostream>
#include <cassert>
#include <iomanip>
#include <set>
#include <iterator>
using namespace std;
#define REP(i,n) for(int i=0;i<n;i++)
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define req(i,a,b) for(int i=a;i>=b;i--)
#define rp(i,a) for(int i=head[a];i+1;i=edge[i].next)
#define cl(a,b) memset(a,b,sizeof a);
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define mod 10007
const int inf = ~0u >> 2;
const ll INF = (1LL << 62) - 1;
double eps = 1e-12;
const int N = 200005 + 5;
const int M = 505;
int s[N]; int n, m;
int a[M][M];
class AlgorithmX {
private:
bool dfs(vector<int> rows,vector<int> cols) {
if (rows.size() == 0 && cols.size() == 0) {
return true;
}
Content content(rows, cols);
int minum = content.findMinColIndex(a);
if (content.calColOneCount(minum) == 0)
return false;
vector<int> removeRows;
vector<int> removeCols;
for (int x = 0; x < rows.size(); x++) {
int i = rows[x];
if (a[i][minum] == 1) {
tmpAnsRows.push_back(i);
for (int y = 0; y < cols.size(); y++)
{
int j = cols[y];
if (a[i][j] == 1)
removeCols.push_back(j);
}
for (int y = 0; y < removeCols.size(); y++) {
int j = removeCols[y];
for (int x2 = 0; x2 < rows.size(); x2++) {
int i2 = rows[x2];
if (a[i2][j] == 1) {
removeRows.push_back(i2);
}
}
}
unique(removeRows.begin(), removeRows.end());
vector<int> lessRows;
set_difference(rows.begin(), rows.end(), removeRows.begin(), removeRows.end(), insert_iterator<vector<int>>(lessRows,lessRows.begin()));
vector<int> lessCols;
set_difference(cols.begin(), cols.end(), removeCols.begin(), removeCols.end(), insert_iterator<vector<int>>(lessCols,lessCols.begin()));
if (dfs(lessRows, lessCols)) {
if (ansRows.size() == 0 || ansRows.size() < tmpAnsRows.size())
ansRows = tmpAnsRows;
cnt++;
}
tmpAnsRows.pop_back();
}
}
return false;
}
public:
void init(int n) {
for (int i = 0; i < n; i++)
rows.push_back(i);
for (int j = 0; j < n; j++)
cols.push_back(j);
}
class Content {
public:
Content(vector<int> rows, vector<int> cols) {
this->rows = rows;
this->cols = cols;
}
private:
vector<int> rows;
vector<int> cols;
public:
int calColOneCount(int pos) {
int num = 0;
for (int j = 0; j < n; j++)
num += a[pos][j];
return num;
}
int findMinColIndex(int a[M][M]) {
int nums[M] = { 0 };
int minum = cols[0];
for (int y = 0; y < cols.size(); y++)
{
int j = cols[y];
nums[j] = 0;
for (int x = 0; x < rows.size(); x++) {
int i = rows[x];
nums[j] += a[i][j];
}
if (nums[j] < nums[minum])
minum = j;
}
return minum;
}
};
void algorithmX() {
dfs(rows,cols);
}
vector<int> rows;
vector<int> cols;
vector<int> tmpAnsRows;
vector<int> ansRows;
int cnt = 0;
}x;
int main() {
int top = 0;
cin >> n;
for(int i=0;i<n;i++)
for (int j = 0; j < n; j++) {
cin >> a[i][j];
}
x.init(n);
x.algorithmX();
return 0;
}

DLX:

#include <cstdio>
#include <memory>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <vector>
#include <cassert>
#include <string>
#include <ctime>
#include <map>
#include <queue>
#include <algorithm>
#include <iostream>
#include <cassert>
#include <iomanip>
#include <set>
#include <iterator>
using namespace std;
#define REP(i,n) for(int i=0;i<n;i++)
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define req(i,a,b) for(int i=a;i>=b;i--)
#define rp(i,a) for(int i=head[a];i+1;i=edge[i].next)
#define cl(a,b) memset(a,b,sizeof a);
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define mod 10007
const int inf = ~0u >> 2;
const ll INF = (1LL << 62) - 1;
double eps = 1e-12;
const int N = 505 + 5;
const int M = 35*35;
int s[N]; int n, m, k;
//int a[M][M];
int b[M*N+M];
class DLX {
private:
const static int maxn = M*N+M;
public:
int l[maxn], r[maxn], u[maxn], d[maxn], s[M];
int row[maxn],col[maxn],head[N];
int sz = 0;
void init(int n,int mm) {
cnt = 0;
ans = inf;
level = 0;
sz = 0;
for (int j = 0; j <= mm; j++)
{
row[j] = 0;
col[j] = j;
s[j] = 0;
l[j] = j - 1;
r[j] = j + 1;
u[j] = d[j] = j;
sz++;
}
sz--;
l[0] = mm;
r[mm] = 0;
for (int i = 1; i <= n; i++)
head[i] = -1;
}
void remove(int y) {//y is column index
r[l[y]] = r[y];
l[r[y]] = l[y];
for (int i = d[y]; i != y; i = d[i]) {
for (int j = r[i]; j != i; j = r[j]) {
d[u[j]] = d[j];
u[d[j]] = u[j];
s[col[j]]--;
}
}
}
void resume(int y) {//y is column index
for (int i = u[y]; i != y; i = u[i]) {
for (int j = l[i]; j != i; j = l[j]) {
d[u[j]] = j;
u[d[j]] = j;
s[col[j]]++;
}
}
l[r[y]] = y;
r[l[y]] = y;
}
void link(int rowIndex, int colIndex) {
col[++sz] = colIndex;
s[colIndex]++;
d[sz] = d[colIndex];
u[sz] = colIndex;
u[d[sz]] = sz;
d[u[sz]] = sz;
if (head[rowIndex] == -1)
{
l[sz] = r[sz] = sz;
head[rowIndex] = sz;
}
else {
l[sz] = head[rowIndex];
r[sz] = r[head[rowIndex]];
l[r[sz]] = sz;
r[l[sz]] = sz;
} }
bool dance() {
if (r[0] == 0) {
return true;
}
int minum = r[0];
for (int i = r[0]; i != 0; i = r[i]) {
if (s[i] < s[minum])
minum = i;
}
if (s[minum] == 0) {
return false;
} level++;
if (level >= ans)
{
level--;
return false;
}
remove(minum); for (int i = d[minum]; i != minum; i = d[i]) {
for (int j = r[i]; j != i; j = r[j]) {
remove(col[j]);
}
bool flag = dance();
for (int j = l[i]; j != i; j = l[j]) {
resume(col[j]);
}
if (flag||level>=ans) {
cnt++;
ans = min(ans, level);
break;
}
} resume(minum);
level--; return false;
}
int getAns() {
return ans;
}
private:
int cnt = 0;
int ans = inf;
int level = 0;
}dlx;
int main() {
int t;
//std::ios::sync_with_stdio(false);
scanf("%d", &t);
while (t--) {
scanf("%d%d%d", &n, &m, &k);
int mm = n*m;
dlx.init(k,mm);
for (int p = 1; p <= k; p++) {
int x, y, xx, yy;
scanf("%d%d%d%d", &x, &y, &xx, &yy); for (int i = x + 1; i <= xx; i++)
{
for (int j = y + 1; j <= yy; j++) {
dlx.link(p, (i - 1)*m + j);
}
}
}
dlx.dance();
printf("%d\n", dlx.getAns()==inf?-1:dlx.getAns());
}
return 0;
}

另外附上Hadoop 上的DancingLinks:

/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.examples.dancing; import java.util.*; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; /**
* A generic solver for tile laying problems using Knuth's dancing link
* algorithm. It provides a very fast backtracking data structure for problems
* that can expressed as a sparse boolean matrix where the goal is to select a
* subset of the rows such that each column has exactly 1 true in it.
*
* The application gives each column a name and each row is named after the
* set of columns that it has as true. Solutions are passed back by giving the
* selected rows' names.
*
* The type parameter ColumnName is the class of application's column names.
*/
public class DancingLinks<ColumnName> {
private static final Log LOG =
LogFactory.getLog(DancingLinks.class.getName()); /**
* A cell in the table with up/down and left/right links that form doubly
* linked lists in both directions. It also includes a link to the column
* head.
*/
private static class Node<ColumnName> {
Node<ColumnName> left;
Node<ColumnName> right;
Node<ColumnName> up;
Node<ColumnName> down;
ColumnHeader<ColumnName> head; Node(Node<ColumnName> l, Node<ColumnName> r, Node<ColumnName> u,
Node<ColumnName> d, ColumnHeader<ColumnName> h) {
left = l;
right = r;
up = u;
down = d;
head = h;
} Node() {
this(null, null, null, null, null);
}
} /**
* Column headers record the name of the column and the number of rows that
* satisfy this column. The names are provided by the application and can
* be anything. The size is used for the heuristic for picking the next
* column to explore.
*/
private static class ColumnHeader<ColumnName> extends Node<ColumnName> {
ColumnName name;
int size; ColumnHeader(ColumnName n, int s) {
name = n;
size = s;
head = this;
} ColumnHeader() {
this(null, 0);
}
} /**
* The head of the table. Left/Right from the head are the unsatisfied
* ColumnHeader objects.
*/
private ColumnHeader<ColumnName> head; /**
* The complete list of columns.
*/
private List<ColumnHeader<ColumnName>> columns; public DancingLinks() {
head = new ColumnHeader<ColumnName>(null, 0);
head.left = head;
head.right = head;
head.up = head;
head.down = head;
columns = new ArrayList<ColumnHeader<ColumnName>>(200);
} /**
* Add a column to the table
* @param name The name of the column, which will be returned as part of
* solutions
* @param primary Is the column required for a solution?
*/
public void addColumn(ColumnName name, boolean primary) {
ColumnHeader<ColumnName> top = new ColumnHeader<ColumnName>(name, 0);
top.up = top;
top.down = top;
if (primary) {
Node<ColumnName> tail = head.left;
tail.right = top;
top.left = tail;
top.right = head;
head.left = top;
} else {
top.left = top;
top.right = top;
}
columns.add(top);
} /**
* Add a column to the table
* @param name The name of the column, which will be included in the solution
*/
public void addColumn(ColumnName name) {
addColumn(name, true);
} /**
* Get the number of columns.
* @return the number of columns
*/
public int getNumberColumns() {
return columns.size();
} /**
* Get the name of a given column as a string
* @param index the index of the column
* @return a string representation of the name
*/
public String getColumnName(int index) {
return columns.get(index).name.toString();
} /**
* Add a row to the table.
* @param values the columns that are satisfied by this row
*/
public void addRow(boolean[] values) {
Node<ColumnName> prev = null;
for(int i=0; i < values.length; ++i) {
if (values[i]) {
ColumnHeader<ColumnName> top = columns.get(i);
top.size += 1;
Node<ColumnName> bottom = top.up;
Node<ColumnName> node = new Node<ColumnName>(null, null, bottom,
top, top);
bottom.down = node;
top.up = node;
if (prev != null) {
Node<ColumnName> front = prev.right;
node.left = prev;
node.right = front;
prev.right = node;
front.left = node;
} else {
node.left = node;
node.right = node;
}
prev = node;
}
}
} /**
* Applications should implement this to receive the solutions to their
* problems.
*/
public interface SolutionAcceptor<ColumnName> {
/**
* A callback to return a solution to the application.
* @param value a List of List of ColumnNames that were satisfied by each
* selected row
*/
void solution(List<List<ColumnName>> value);
} /**
* Find the column with the fewest choices.
* @return The column header
*/
private ColumnHeader<ColumnName> findBestColumn() {
int lowSize = Integer.MAX_VALUE;
ColumnHeader<ColumnName> result = null;
ColumnHeader<ColumnName> current = (ColumnHeader<ColumnName>) head.right;
while (current != head) {
if (current.size < lowSize) {
lowSize = current.size;
result = current;
}
current = (ColumnHeader<ColumnName>) current.right;
}
return result;
} /**
* Hide a column in the table
* @param col the column to hide
*/
private void coverColumn(ColumnHeader<ColumnName> col) {
LOG.debug("cover " + col.head.name);
// remove the column
col.right.left = col.left;
col.left.right = col.right;
Node<ColumnName> row = col.down;
while (row != col) {
Node<ColumnName> node = row.right;
while (node != row) {
node.down.up = node.up;
node.up.down = node.down;
node.head.size -= 1;
node = node.right;
}
row = row.down;
}
} /**
* Uncover a column that was hidden.
* @param col the column to unhide
*/
private void uncoverColumn(ColumnHeader<ColumnName> col) {
LOG.debug("uncover " + col.head.name);
Node<ColumnName> row = col.up;
while (row != col) {
Node<ColumnName> node = row.left;
while (node != row) {
node.head.size += 1;
node.down.up = node;
node.up.down = node;
node = node.left;
}
row = row.up;
}
col.right.left = col;
col.left.right = col;
} /**
* Get the name of a row by getting the list of column names that it
* satisfies.
* @param row the row to make a name for
* @return the list of column names
*/
private List<ColumnName> getRowName(Node<ColumnName> row) {
List<ColumnName> result = new ArrayList<ColumnName>();
result.add(row.head.name);
Node<ColumnName> node = row.right;
while (node != row) {
result.add(node.head.name);
node = node.right;
}
return result;
} /**
* Find a solution to the problem.
* @param partial a temporary datastructure to keep the current partial
* answer in
* @param output the acceptor for the results that are found
* @return the number of solutions found
*/
private int search(List<Node<ColumnName>> partial, SolutionAcceptor<ColumnName> output) {
int results = 0;
if (head.right == head) {
List<List<ColumnName>> result = new ArrayList<List<ColumnName>>(partial.size());
for(Node<ColumnName> row: partial) {
result.add(getRowName(row));
}
output.solution(result);
results += 1;
} else {
ColumnHeader<ColumnName> col = findBestColumn();
if (col.size > 0) {
coverColumn(col);
Node<ColumnName> row = col.down;
while (row != col) {
partial.add(row);
Node<ColumnName> node = row.right;
while (node != row) {
coverColumn(node.head);
node = node.right;
}
results += search(partial, output);
partial.remove(partial.size() - 1);
node = row.left;
while (node != row) {
uncoverColumn(node.head);
node = node.left;
}
row = row.down;
}
uncoverColumn(col);
}
}
return results;
} /**
* Generate a list of prefixes down to a given depth. Assumes that the
* problem is always deeper than depth.
* @param depth the depth to explore down
* @param choices an array of length depth to describe a prefix
* @param prefixes a working datastructure
*/
private void searchPrefixes(int depth, int[] choices,
List<int[]> prefixes) {
if (depth == 0) {
prefixes.add(choices.clone());
} else {
ColumnHeader<ColumnName> col = findBestColumn();
if (col.size > 0) {
coverColumn(col);
Node<ColumnName> row = col.down;
int rowId = 0;
while (row != col) {
Node<ColumnName> node = row.right;
while (node != row) {
coverColumn(node.head);
node = node.right;
}
choices[choices.length - depth] = rowId;
searchPrefixes(depth - 1, choices, prefixes);
node = row.left;
while (node != row) {
uncoverColumn(node.head);
node = node.left;
}
row = row.down;
rowId += 1;
}
uncoverColumn(col);
}
}
} /**
* Generate a list of row choices to cover the first moves.
* @param depth the length of the prefixes to generate
* @return a list of integer arrays that list the rows to pick in order
*/
public List<int[]> split(int depth) {
int[] choices = new int[depth];
List<int[]> result = new ArrayList<int[]>(100000);
searchPrefixes(depth, choices, result);
return result;
} /**
* Make one move from a prefix
* @param goalRow the row that should be choosen
* @return the row that was found
*/
private Node<ColumnName> advance(int goalRow) {
ColumnHeader<ColumnName> col = findBestColumn();
if (col.size > 0) {
coverColumn(col);
Node<ColumnName> row = col.down;
int id = 0;
while (row != col) {
if (id == goalRow) {
Node<ColumnName> node = row.right;
while (node != row) {
coverColumn(node.head);
node = node.right;
}
return row;
}
id += 1;
row = row.down;
}
}
return null;
} /**
* Undo a prefix exploration
* @param row
*/
private void rollback(Node<ColumnName> row) {
Node<ColumnName> node = row.left;
while (node != row) {
uncoverColumn(node.head);
node = node.left;
}
uncoverColumn(row.head);
} /**
* Given a prefix, find solutions under it.
* @param prefix a list of row choices that control which part of the search
* tree to explore
* @param output the output for each solution
* @return the number of solutions
*/
public int solve(int[] prefix, SolutionAcceptor<ColumnName> output) {
List<Node<ColumnName>> choices = new ArrayList<Node<ColumnName>>();
for(int i=0; i < prefix.length; ++i) {
choices.add(advance(prefix[i]));
}
int result = search(choices, output);
for(int i=prefix.length-1; i >=0; --i) {
rollback(choices.get(i));
}
return result;
} /**
* Solve a complete problem
* @param output the acceptor to receive answers
* @return the number of solutions
*/
public int solve(SolutionAcceptor<ColumnName> output) {
return search(new ArrayList<Node<ColumnName>>(), output);
} }

DLX AlgorithmX的更多相关文章

  1. DLX (poj 3074)

    题目:Sudoku 匪夷所思的方法,匪夷所思的速度!!! https://github.com/ttlast/ACM/blob/master/Dancing%20Link%20DLX/poj%2030 ...

  2. HDU 3957 Street Fighter(搜索、DLX、重复覆盖+精确覆盖)

    很久以前就看到的一个经典题,一直没做,今天拿来练手.街霸 给n<=25个角色,每个角色有 1 or 2 个版本(可以理解为普通版以及爆发版),每个角色版本可以KO掉若干人. 问最少选多少个角色( ...

  3. 数独求解 DFS && DLX

    题目:Sudoku 题意:求解数独.从样例和结果来看应该是简单难度的数独 思路:DFS 设置3个数组,row[i][j] 判断第i行是否放了j数字,col[i][j] 判断第i列是否放了j数字.squ ...

  4. DLX模型问题

    问题:sevenzero liked Warcraft very much, but he haven't practiced it for several years after being add ...

  5. HDU 4069 Squiggly Sudoku(DLX)(The 36th ACM/ICPC Asia Regional Fuzhou Site —— Online Contest)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4069 Problem Description Today we play a squiggly sud ...

  6. HDU 5046 Airport(dlx)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5046 题意:n个城市修建m个机场,使得每个城市到最近进场的最大值最小. 思路:二分+dlx搜索判定. ...

  7. POJ2676,HDU4069解决数独的两种实现:DFS、DLX

    搜索实现:解决数独有两种思考策略,一种是枚举当前格能填的数字的种数,这里有一优化策略就是先搜索能填入种数小的格子:另一种是考虑处理某一行(列.宫)时,对于某一个没用过的数字,若该行(列.宫)只有一个可 ...

  8. HDU2295 Radar (DLX)

    下面的代码99%参考了这个网站http://www.cnblogs.com/183zyz/archive/2011/08/07/2130193.html 人生的第一道DLX肯定是需要作一些参考的啦. ...

  9. DLX舞蹈链 hdu5046

    题意: 在N个城市选出K个城市,建飞机场(1 ≤ N ≤ 60,1 ≤ K ≤ N),N个城市给出坐标,选择这K个机场,使得从城市到距离自己最近的机场的 最大的距离 最小. 输出这个最小值. 思路: ...

随机推荐

  1. .NETCore中实现ObjectId反解

    前言 在设计数据库的时候,我们通常需要给业务数据表分配主键,很多时候,为了省事,我都是直接使用 GUID/UUID 的方式,但是在 MonggoDB 中,其内部实现了 ObjectId(以下统称为Oi ...

  2. 18、Java中的 数据结构

    Java2中引入了新的数据结构 集合框架 Collection,下一节再谈论(非常重要,面试也常问). 1.枚举 (Enumeration) 1.1 Enumeration 源码: public in ...

  3. Jenkins持续集成(上)-Windows下安装Jenkins

    环境:Windows 2008 R2.Jenkins2.235.1: 概要 前面写过一篇文章,<自动发布-asp.net自动发布.IIS站点自动发布(集成SLB.配置管理.Jenkins)> ...

  4. 不能错过的分布式ID生成器(Leaf ),好用的一批!

    本文收录在个人博客:www.chengxy-nds.top,技术资料共享,同进步 不了解分布式ID的同学,先行去看<一口气说出 9种 分布式ID生成方式,面试官有点懵了>温习一下基础知识, ...

  5. 配置JDK的环境变量

    1.官网下载JDK安装包并进行安装,记住安装目录 2.安装完JDK后配置环境变量  计算机→属性→高级系统设置→高级→环境变量 3.系统变量→新建 JAVA_HOME 变量 .变量值填写jdk的安装目 ...

  6. C#LeetCode刷题-动态规划

    动态规划篇 # 题名 刷题 通过率 难度 5 最长回文子串   22.4% 中等 10 正则表达式匹配   18.8% 困难 32 最长有效括号   23.3% 困难 44 通配符匹配   17.7% ...

  7. jraft日志复制

    jraft的日志复制是指从leader往follower复制logEntry的过程. 日志复制从节点成为leader开始.在nodeImpl的becomeLeader中 private void be ...

  8. windows 服务端 狼人杀 发牌器 开发完成 待继续开发其他服务

    开发工具: python2.7 eric4 成果链接地址 https://wws.lanzous.com/iPCDTfnuoif

  9. JavaScript设计模式之策略模式【组合委托】

    前言:语言只是工具,思想才是核心 今天要总结的是 策略模式 策略在开发中的应用非常广泛,所以也是非常常见且使用的设计模式. 在实际开发中,往往在实现一个功能时,有多种解决方案可行. 常见场景: 解压: ...

  10. nohup 命令的使用

    nohup 命令的使用 1. nohup简介 nohup 命令运行由 Command参数和任何相关的 Arg参数指定的命令,忽略所有挂断(SIGHUP)信号.在注销后使用 nohup 命令运行后台中的 ...