• DLX AlgorithmX


    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
    ", 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);
      }
      
    }
    
  • 相关阅读:
    一道经典的JavaScript面试题
    模拟学信网登录,Cookie 序列化,在反序列化之后不能用的问题
    EF搜索数据自动将表名变复数问题
    EF查看sql的方法
    查看当前正在被执行的sql
    mmsql查看最近操作日志
    查询存储过程里面的含有的关键字
    mmsql 查询每个分类的前3条数据
    C# checked关键字当属性
    windows2012 IIS8.5 不能在此路径中使用此配置节
  • 原文地址:https://www.cnblogs.com/HaibaraAi/p/6512364.html
Copyright © 2020-2023  润新知