abastract:利用dancing links 解决精确覆盖问题,例如数独,n皇后问题;以及重复覆盖问题。

要学习dacning links 算法,首先要先了解该算法适用的问题,精确覆盖问题和重复覆盖问题等,下面先了解精确覆盖问题和重复覆盖问题。

精确覆盖问题

何为精确覆盖问题

  在一个全集X中若干子集的集合为S,精确覆盖(Exactcover)是指,S的子集S*,满足X中的每一个元素在S*中恰好出现一次。

定义 

  满足以下条件的集合为一个精确覆盖: 
    S*中任意两个集合没有交集,即X中的元素在S*中出现最多一次 
    S*中集合的全集为X,即X中的元素在S*中出现最少一次 
    合二为一,即X中的元素在S*中出现恰好一次。
  举例
  令={N,O,E,P}是集合X={1,2,3,4}的一个子集,并满足: 
    N={} 
    O={1,3} 
    E={2,4} 
    P={2,3}. 
    其中一个子集{O,E}是X的一个精确覆盖,因为O={1,3}而E={2,4}的并集恰好是X={1,2,3,4}。同理,{N,O,E}也是X.的一个精确覆盖。空集并不影响结论。

精确覆盖问题的表示方式

  一般的,我们用一个集合s包含s中的元素的单向关系表示精确覆盖问题。常用的有以下两种方法:

  • 矩阵表示法

  包含关系可以用一个关系矩阵表示。.矩阵每行表示S的一个子集,每列表示X中的一个元素。矩阵行列交点元素为1表示对应的元素在对应的集合中,不在则为0。

  通过这种矩阵表示法,求一个精确覆盖转化为求矩阵的若干个行的集合,使每列有且仅有一个1。同时,该问题也是精确覆盖的典型例题之一。

  下表为其中一个例子:

   

  S*={B,D,F}便是一个精确覆盖。

  • 图论表示法

  可将精确覆盖问题转化为一个二分图,左侧为集合,右侧为元素,左侧集合若与右侧元素有包含关系则连边,通过将左侧节点与其所有边保留与否求解一个右侧的每一个节点恰好有一条边的匹配。

重复覆盖问题

 即选取一个01矩阵中的几行,使这几行组成的新矩阵的每一列至少有一个1。 该问题在精确覆盖问题上减少了一个约束条件。

  接下来就是dancing links x算法了。


  Dancing Links X 算法

历史

  X算法是高德纳提出的解决精确覆盖问题的算法,而dancing links X算法则是DonKnuth(《计算机程序设计艺术》的作者)提出的对X算法的一种高效实现,这种实现建立在如上所说的矩阵表示法上。

算法思想

  由如上精确覆盖问题的矩阵表示法中,我们知道dancing links x 是用来求解一个 01矩阵中选取哪几行可以使得这几行每一列都有且仅有一个1(就是每个元素在这几个子集里有且仅有出现过一次)。

  先不管他的实际意义,我们需要做的就是在一个01矩阵的选取某几行使之符合上述条件。

  我们很容易就想到枚举,然后判断符不符合条件,但是这个做法实在是太消耗时间。

  dacing links x就是一个高效的求解该类问题的算法,而这种算法,基于交叉十字循环双向链的数据结构。  

  例如:如下的矩阵

  就包含了这样一个集合(第1、4、5行)

  如何利用给定的矩阵求出相应的行的集合呢?我们采用回溯法

  

  先假定选择第1行,如下所示:

  如上图中所示,红色的那行是选中的一行,这一行中有3个1,分别是第3、5、6列。

  由于这3列已经包含了1,故,把这三列往下标示,图中的蓝色部分。蓝色部分包含3个1,分别在2行中,把这2行用紫色标示出来

  根据定义,同一列的1只能有1个,故紫色的两行,和红色的一行的1相冲突。

  那么在接下来的求解中,红色的部分、蓝色的部分、紫色的部分都不能用了,把这些部分都删除,得到一个新的矩阵

  

  行分别对应矩阵1中的第2、4、5行

  列分别对应矩阵1中的第1、2、4、7列 

  于是问题就转换为一个规模小点的精确覆盖问题

  在新的矩阵中再选择第1行,如下图所示

  还是按照之前的步骤,进行标示。红色、蓝色和紫色的部分又全都删除,导致新的空矩阵产生,而红色的一行中有0(有0就说明这一列没有1覆盖)。说明,第1行选择是错误的

  那么回到之前,选择第2行,如下图所示  

  按照之前的步骤,进行标示。把红色、蓝色、紫色部分删除后,得到新的矩阵

  

  行对应矩阵2中的第3行,矩阵1中的第5行

  列对应矩阵2中的第2、4列,矩阵1中的第2、7列

   由于剩下的矩阵只有1行,且都是1,选择这一行,问题就解决

  于是该问题的解就是矩阵1中第1行、矩阵2中的第2行、矩阵3中的第1行。也就是矩阵1中的第1、4、5行()

(例子引用自http://www.cnblogs.com/grenet/p/3145800.html)

  而对于重复覆盖问题,在选定某一行之后只需删除该行含1的所在列,并不需要再删除所在列上含1的行。


2016-08-21 21:00:15

Example1:HUST  1017

  裸精确覆盖问题,问题如下:

1017 - Exact cover

题目描述:

  There is an N*M matrix with only 0s and 1s, (1 <= N,M <= 1000). An exact cover is a selection of rows such that every column has a 1 in exactly one of the selected rows. Try to find out the selected rows.输入There are multiply test cases. First line: two integers N, M; The following N lines: Every line first comes an integer C(1 <= C <= 100), represents the number of 1s in this row, then comes C integers: the index of the columns whose value is 1 in this row.输出First output the number of rows in the selection, then output the index of the selected rows. If there are multiply selections, you should just output any of them. If there are no selection, just output "NO".

样例输入

6 7

3 1 4 7

2 1 4

3 4 5 7

3 3 5 6

4 2 3 6 7

2 2 7

样例输出

3 2 4 6

提示来源

dupeng

  裸精确覆盖问题,直接用dancing links 做。

 #include<cstdio>
#include<iostream>
#include<cstring>
#define clr(x) memset(x,0,sizeof(x))
#define clrlow(x) memset(x,-1,sizeof(x))
#define maxnode 1001010
#define maxn 1010
using namespace std;
struct DLX{
int n,m;
int U[maxnode],D[maxnode],L[maxnode],R[maxnode],col[maxnode],row[maxnode];
int H[maxn];
int ansed,ans[maxn],size;
void init(int _n,int _m)
{
n=_n;
m=_m;
for(int i=;i<=m;i++)
{
U[i]=i;
D[i]=i;
L[i]=i-;
R[i]=i+;
col[i]=i;
row[i]=;
}
L[]=m;
R[m]=;
size=m;
clrlow(H);
clr(ans);
ansed=;
return ;
}
void push(int r,int c)
{
size++;
D[size]=D[c];
U[size]=c;
U[D[c]]=size;
D[c]=size;
row[size]=r;
col[size]=c;
if(H[r]<)
{
H[r]=size;
R[size]=L[size]=size;
}
else
{
L[size]=H[r];
R[size]=R[H[r]];
L[R[H[r]]]=size;
R[H[r]]=size;
}
}
void del(int c)
{
R[L[c]]=R[c];
L[R[c]]=L[c];
for(int i=D[c];i!=c;i=D[i])
for(int j=R[i];j!=i;j=R[j])
{
D[U[j]]=D[j];
U[D[j]]=U[j];
}
return ;
}
void reback(int c)
{
for(int i=U[c];i!=c;i=U[i])
for(int j=L[i];j!=i;j=L[j])
{
D[U[j]]=j;
U[D[j]]=j;
}
R[L[c]]=c;
L[R[c]]=c;
return ;
}
bool dancing(int dep)
{
if(R[]==)
{
ansed=dep;
return true;
}
int c=R[];
del(c);
for(int i=D[c];i!=c;i=D[i])
{
ans[dep]=row[i];
for(int j=R[i];j!=i;j=R[j])
del(col[j]);
if(dancing(dep+))
return true;
for(int j=L[i];j!=i;j=L[j])
reback(col[j]);
}
return false;
}
}dlx;
int main()
{
int n,m,p,k;
while(scanf("%d%d",&n,&m)==)
{
dlx.init(n,m);
for(int i=;i<=n;i++)
{
scanf("%d",&p);
for(int j=;j<=p;j++)
{
scanf("%d",&k);
dlx.push(i,k);
}
}
if(!dlx.dancing())
printf("NO\n");
else
{
printf("%d",dlx.ansed);
for(int i=;i<dlx.ansed;i++)
printf(" %d",dlx.ans[i]);
printf("\n");
}
}
return ;
}

除此之外,运用这个dancing links 的这个模板,还可以解决数独,n皇后问题。

浅谈数独解法  

  我们在做数独时一般会使用枚举法。在某个格子枚举当前情况下的所有可填入数字,而在枚举其中一个可填入数字后递归到下一层,也就是下一个格子,枚举上一个格子数字确定下来的九宫格在该格子的所有可填入数字,以此类推。直到九宫格完全填满时,这时候的解为该九宫格的一个可行解,可继续递归返回上一层寻找下一个可行解。这个做法效率不错,但是若直接枚举,写起来就又臭又长(好吧我承认其实DLX也挺长的),若九宫格过于稀疏,该做法的时间效率也会指数级上升。我们选择用DLX把每一个已填格子和未填格子的信息转化成行,接下来dance一遍找出符合条件的行,再转化回九宫格信息,就是一个可行解了。最多729行进行DLX(9*9*9,后面你会明白的),速度较直接枚举也快很多,除去DLX的结构体,其他代码长度也比直接枚举短很多(打模板比较快hhh)。

  那么怎么把九宫格上的信息转化成行呢? 首先数独中可行的解需满足:每一行,每一列,每一个宫里面不能有相同的数字,且只能使用1-9这九个数字。

  把它转化为符合精确覆盖问题的条件,即为:

  1. 每一个格只能填一个数字。
  2. 每个数字在每一行只能出现一次。
  3. 每个数字在每一列只能出现一次。
  4. 每个数字在每一宫只能出现一次。

  对于第一个条件:

  第一列表示填入(1,1)这一格。

  第二列表示填入(1,2)这一格。

  第三列表示填入(1,3)这一格。

……

  第(m-1)*9+n列表示填入(m,n)这一格。(1<=m<=9,1<=n<=9)

  ……

  第9*9-1列表示填入(9,8)这一格。

  第9*9列表示填入(9,9)这一格。

  设inf1=81;

以此类推……

  第二个条件:

  第inf+1列表示在第一行填入1。

  第inf+2列表示在第一行填入2。

  第inf+3列表示在第一行填入3。

  ……

  第inf+(n-1)*9+m列表示在第n行填入m(1<=n<=9,1<=m<=9)。

  ……

  第inf+9*9表示在第九行填入9。

  设inf2=inf1+81;

对于第三个条件也是如此,inf3=inf2+81;

  对于第四个条件,inf4=inf3+81;

 至此,已经把所有的条件都转化成了列。

 而对于一个有数字的格子(假设位于(m,n)数字为k,位于第p宫)只需把它转化为一行,该行于(m-1)*9+n,inf1+(m-1)*9+k,inf2+(n-1)*9+k,inf3+(p-1)*9+k这四列为1,其余为0。

 对于一个没有数字的格子(假设位于(m',n')第p'宫),则需把他转化为九行,分别代表在这一格填入1-9各个数字,每一列的填列原理和有数字的格子一样。

 在把所有的格子转化完毕后,先把所有确定的有数字的格子的行以及该行含1的列以及该列上含1的行从矩阵中删除,然后dance一遍,找出符合的行,再把行转化成每个格子的信息,填入九宫格中,就是符合的一个解了。

2016-08-27 17:07:53

n皇后解法

  类似于数独问题,在n皇后问题中,不冲突的n皇后的棋盘上符合以下五个个条件:

  1. 每一个格子最多只能有一个皇后。
  2. 每一行最多只能有一个皇后。
  3. 每一列最多只能有一个皇后。
  4. 每一个从左上往右下的斜边最多只能有一个皇后。
  5. 每一个从右上往左下的斜边最多只能有一个皇后。

  这五个条件看起来不太好用dlx的做法去做,但如果把整个棋盘中有皇后的位置用1表示,没有皇后的位置用1表示,则可以转化为:

  1. 每个格子只能填一个数字。
  2. 每一行有且仅能填一个1。
  3. 每一列有且仅能填一个1。
  4. 每一个从左上往右下的斜边有且仅能填一个1。
  5. 每一个从右上往左下的斜边有且仅能填一个1。

   按照数独的过程进行DLX,找出填1的行数大于等于n的解。等于n的解即为n皇后问题的解,大于n的解删去几行使填1的行数为n即为n皇后问题的解。


重复覆盖问题

  顾名思义,即为在01矩阵中,选出几行,使得在这几行组成的新矩阵中,每一列都有1。

  下面是hdu上一个重复覆盖的二分问题,并且给出重复覆盖问题的代码部分:

 Example2:hdu 2295

Radar

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2280    Accepted Submission(s): 897

Problem Description
N cities of the Java Kingdom need to be covered by radars for being in a state of war. Since the kingdom has M radar stations but only K operators, we can at most operate K radars. All radars have the same circular coverage with a radius of R. Our goal is to minimize R while covering the entire city with no more than K radars.
 
Input
The input consists of several test cases. The first line of the input consists of an integer T, indicating the number of test cases. The first line of each test case consists of 3 integers: N, M, K, representing the number of cities, the number of radar stations and the number of operators. Each of the following N lines consists of the coordinate of a city.
Each of the last M lines consists of the coordinate of a radar station.

All coordinates are separated by one space.
Technical Specification

1. 1 ≤ T ≤ 20
2. 1 ≤ N, M ≤ 50
3. 1 ≤ K ≤ M
4. 0 ≤ X, Y ≤ 1000

 
Output
For each test case, output the radius on a single line, rounded to six fractional digits.
 
Sample Input
1 3 3 2 3 4 3 1 5 4 1 1 2 2 3 3
 
Sample Output
2.236068
 
Source
 

该题用二分查找radar的半径,然后用重复覆盖的DLX进行最多选取k行该半径是否完全覆盖所有城市的判断(f()函数和dep一起判断),最后精确到小数点后六位。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#define clr(x) memset(x,0,sizeof(x))
#define clrlow(x) memset(x,-1,sizeof(x))
#define maxnode 3000
#define maxn 60
using namespace std;
struct DLX//dancing links
{
int U[maxnode],D[maxnode],L[maxnode],R[maxnode],col[maxnode],row[maxnode];//元素上下左右对应列对应行的指针
int S[maxn],H[maxn],V[maxn];//S为每列元素个数,H指向每行末尾的元素,V是dep()函数的标记数组。
int n,m,size,all;//all为解的行数的最大值
void init(int _n,int _m,int _all)
{
n=_n;
m=_m;
all=_all;
for(int i=;i<=m;i++)
{
L[i]=i-;
R[i]=i+;
U[i]=i;
D[i]=i;
row[i]=;
col[i]=i;
}
clr(S);
clrlow(H);
L[]=m;
R[m]=;
size=m;
return ;
}
//初始化
void push(int r,int c)
{
D[++size]=D[c];
col[size]=U[size]=c;
U[D[c]]=size;
D[c]=size;
row[size]=r;
S[c]++;
if(H[r]<)
{
H[r]=L[size]=R[size]=size;
}
else
{
L[size]=H[r];
R[size]=R[H[r]];
L[R[H[r]]]=size;
R[H[r]]=size;
}
return ;
}
//加入元素
void del(int c)
{
S[col[c]]--;
for(int i=D[c];i!=c;i=D[i])
{
R[L[i]]=R[i];
L[R[i]]=L[i];
S[col[i]]--;
}
return ;
}
//删除一列
void reback(int c)
{
for(int i=U[c];i!=c;i=U[i])
{
S[col[R[L[i]]=L[R[i]]=i]]++;
}
S[col[c]]++;
return ;
}
//恢复一列
int dep( )
{
clr(V);
int deep=;
for(int i=R[];i!=;i=R[i])
if(!V[i])
{
deep++;
for(int j=D[i];j!=i;j=D[j])
for(int k=R[j];k!=j;k=R[k])
V[col[k]]=;
}
return deep;
}
//之后到达的最大深度
//d为当前深度
bool dancing(int d)
{
if(d+dep()>all) return false;
int c=R[];
if(c==)
{
return d<=all;
}
for(int i=R[];i!=;i=R[i])
if(S[i]<S[c])
c=i;
for(int i=D[c];i!=c;i=D[i])
{
del(i);
for(int j=R[i];j!=i;j=R[j])
del(j);
if(dancing(d+)) return true;
for(int j=L[i];j!=i;j=L[j])
reback(j);
reback(i);
}
return false;
}
//dancing
}dlx;
struct point
{
int x,y;
}station[maxn],city[maxn];
double dis(point a,point b)
{
return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
int main()
{
int n,m,k,kase;
double lt,rt,mid;
double eps=1e-;
scanf("%d",&kase);
while(kase--)
{
scanf("%d%d%d",&n,&m,&k);
for(int i=;i<=n;i++)
scanf("%d%d",&city[i].x,&city[i].y);
for(int i=;i<=m;i++)
scanf("%d%d",&station[i].x,&station[i].y);
lt=;
rt=1e8;
while(rt-lt>=eps)
{
dlx.init(m,n,k);
mid=(rt+lt)/;
for(int i=;i<=m;i++)
for(int j=;j<=n;j++)
if(dis(city[j],station[i])<mid*mid-eps)
dlx.push(i,j);
if(dlx.dancing())
rt=mid-eps;
else
lt=mid+eps;
}
printf("%.6lf\n",lt);
}
return ;
}

FZU上一道练手题

Problem 1686 神龙的难题

Accept: 717    Submit: 2140
Time Limit: 1000 mSec    Memory Limit : 32768 KB

 Problem Description

这是个剑与魔法的世界.英雄和魔物同在,动荡和安定并存.但总的来说,库尔特王国是个安宁的国家,人民安居乐业,魔物也比较少.但是.总有一些魔物不时会进入城市附近,干扰人民的生活.就要有一些人出来守护居民们不被魔物侵害.魔法使艾米莉就是这样的一个人.她骑着她的坐骑,神龙米格拉一起消灭干扰人类生存的魔物,维护王国的安定.艾米莉希望能够在损伤最小的前提下完成任务.每次战斗前,她都用时间停止魔法停住时间,然后米格拉他就可以发出火球烧死敌人.米格拉想知道,他如何以最快的速度消灭敌人,减轻艾米莉的负担.

 Input

数据有多组,你要处理到EOF为止.每组数据第一行有两个数,n,m,(1<=n,m<=15)表示这次任务的地区范围. 然后接下来有n行,每行m个整数,如为1表示该点有怪物,为0表示该点无怪物.然后接下一行有两个整数,n1,m1 (n1<=n,m1<=m)分别表示米格拉一次能攻击的行,列数(行列不能互换),假设米格拉一单位时间能发出一个火球,所有怪物都可一击必杀.

 Output

输出一行,一个整数,表示米格拉消灭所有魔物的最短时间.

 Sample Input

4 4
1 0 0 1
0 1 1 0
0 1 1 0
1 0 0 1
2 2
4 4
0 0 0 0
0 1 1 0
0 1 1 0
0 0 0 0
2 2

 Sample Output

4
1

 Source

FOJ月赛-2009年2月- TimeLoop

依旧是重复覆盖问题模板

 #include<cstdio>
#include<iostream>
#include<cstring>
#define clr(x) memset(x,0,sizeof(x))
#define clrlow(x) memset(x,-1,sizeof(x))
#define maxm (15*15+10)
#define maxn (15*15+10)
#define maxnode maxn*maxm
#define INF 1000000000
using namespace std;
struct DLX
{
int size,n,m;
int D[maxnode],U[maxnode],L[maxnode],R[maxnode],row[maxnode],col[maxnode];
int H[maxn],S[maxm];
int ansed;
void init(int _n,int _m)
{
n=_n;
m=_m;
size=m;
for(int i=;i<=m;i++)
{
D[i]=i;
U[i]=i;
R[i]=i+;
L[i]=i-;
row[i]=;
col[i]=i;
S[i]=;
}
L[]=m; R[m]=;
for(int i = ;i <= n;i++)H[i] = -;
ansed=INF;
return ;
}
void push(int r,int c)
{
++S[col[++size]=c];
row[size]=r;
D[size]=D[c];
U[size]=c;
U[D[c]]=size;
D[c]=size;
if(H[r]<)
{
L[size]=R[size]=size;
H[r]=size;
}
else
{
R[size]=R[H[r]];
L[size]=H[r];
L[R[H[r]]]=size;
R[H[r]]=size;
}
return;
}
void del(int p)
{
for(int i=D[p];i!=p;i=D[i])
{
R[L[i]]=R[i];
L[R[i]]=L[i];
}
return ;
}
void remove(int p)
{
for(int i=U[p];i!=p;i=U[i])
{
R[L[i]]=L[R[i]]=i;
}
return ;
}
bool v[maxm];
int dis()
{
int ans=;
for(int i=;i<=m;i++) v[i]=;
for(int i=R[];i!=;i=R[i])
if(!v[i])
{
ans++;
for(int j=D[i];j!=i;j=D[j])
for(int k=R[j];k!=j;k=R[k])
v[col[k]]=;
}
return ans;
}
void dancing(int dep)
{
if(dep+dis()>=ansed) return;
if(R[]==)
{
if(dep<ansed) ansed=dep;
return ;
}
int c=R[];
for(int i=R[];i!=;i=R[i])
if(S[i]<S[c])
c=i;
for(int i=D[c];i!=c;i=D[i])
{
del(i);
for(int j=R[i];j!=i;j=R[j])
del(j);
dancing(dep+);
for(int j=L[i];j!=i;j=L[j])
remove(j);
remove(i);
}
return ;
}
}dlx;
int n,m,n1,m1,a[maxn][maxm],num[maxn][maxm],inf;
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
inf=;
clr(a);
clr(num);
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
{
scanf("%d",&a[i][j]);
if(a[i][j]==) num[i][j]=(++inf);
}
dlx.init(n*m,inf);
scanf("%d%d",&n1,&m1);
inf=;
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
{
inf++;
for(int k=i;k<i+n1 && k<=n;k++)
for(int l=j;l<j+m1 && l<=m;l++)
if(num[k][l])
dlx.push(inf,num[k][l]);
}
dlx.dancing();
printf("%d\n",dlx.ansed);
}
return ;
}

浅入 dancing links x(舞蹈链算法)的更多相关文章

  1. 算法帖——用舞蹈链算法(Dancing Links)求解俄罗斯方块覆盖问题

    问题的提出:如下图,用13块俄罗斯方块覆盖8*8的正方形.如何用计算机求解? 解决这类问题的方法不一而足,然而核心思想都是穷举法,不同的方法仅仅是对穷举法进行了优化 用13块不同形状的俄罗斯方块(每个 ...

  2. 跳跃的舞者,舞蹈链(Dancing Links)算法——求解精确覆盖问题

    精确覆盖问题的定义:给定一个由0-1组成的矩阵,是否能找到一个行的集合,使得集合中每一列都恰好包含一个1 例如:如下的矩阵 就包含了这样一个集合(第1.4.5行) 如何利用给定的矩阵求出相应的行的集合 ...

  3. Dancing Links算法(舞蹈链)

    原文链接:跳跃的舞者,舞蹈链(Dancing Links)算法——求解精确覆盖问题 作者:万仓一黍 出处:http://grenet.cnblogs.com/ 本文版权归作者和博客园共有,欢迎转载,但 ...

  4. 转载 - 跳跃的舞者,舞蹈链(Dancing Links)算法——求解精确覆盖问题

    出处:http://www.cnblogs.com/grenet/p/3145800.html 精确覆盖问题的定义:给定一个由0-1组成的矩阵,是否能找到一个行的集合,使得集合中每一列都恰好包含一个1 ...

  5. [转] 舞蹈链(Dancing Links)——求解精确覆盖问题

    转载自:http://www.cnblogs.com/grenet/p/3145800.html 精确覆盖问题的定义:给定一个由0-1组成的矩阵,是否能找到一个行的集合,使得集合中每一列都恰好包含一个 ...

  6. DLX舞蹈链 hdu5046

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

  7. 算法实践——舞蹈链(Dancing Links)算法求解数独

    在“跳跃的舞者,舞蹈链(Dancing Links)算法——求解精确覆盖问题”一文中介绍了舞蹈链(Dancing Links)算法求解精确覆盖问题. 本文介绍该算法的实际运用,利用舞蹈链(Dancin ...

  8. 转载 - 算法实践——舞蹈链(Dancing Links)算法求解数独

    出处:http://www.cnblogs.com/grenet/p/3163550.html 在“跳跃的舞者,舞蹈链(Dancing Links)算法——求解精确覆盖问题”一文中介绍了舞蹈链(Dan ...

  9. Dancing Links and Exact Cover

    1. Exact Cover Problem DLX是用来解决精确覆盖问题行之有效的算法. 在讲解DLX之前,我们先了解一下什么是精确覆盖问题(Exact Cover Problem)? 1.1 Po ...

随机推荐

  1. Delphi 10.3 Rio + iOS 12.1 SDK 编译错误 "libcharset.1.dylib"

    环境版本: Delphi 10.3 Rio iOS 12.1 SDK Xcode 10.1 (10B61) 错误讯息:[DCC Error] E2597 ld: file not found: /us ...

  2. 20155202《网络对抗》Exp9 web安全基础实践

    20155202<网络对抗>Exp9 web安全基础实践 实验前回答问题 (1)SQL注入攻击原理,如何防御 SQL注入产生的原因,和栈溢出.XSS等很多其他的攻击方法类似,就是未经检查或 ...

  3. 2017-2018-2 20155231《网络对抗技术》实验五: MSF基础应用

    2017-2018-2 20155231<网络对抗技术>实验五: MSF基础应用 实践目标 掌握信息搜集的最基础技能与常用工具的使用方法. 实验内容 (1)各种搜索技巧的应用 比如IP2L ...

  4. 20155334 曹翔 Exp3 免杀原理与实践

    20155334 曹翔 Exp3 免杀原理与实践 小记:这次实验,困难重重,失败练练,搞得我们是心急如焚,焦头烂额,哭爹喊娘 一.基础问题回答 杀软是如何检测出恶意代码的? 每个杀软都有自己的检测库, ...

  5. SimpleDateFormat-时间格式化中的大小写字符

    一.SimpleDateFormat: 这个类是用来格式化date类型数据为指定格式的时间的 使用的而时候,总是区分不清 yyyy-mm-dd yyyy-MM-dd 而使用不同的大小写字符格式化出来的 ...

  6. 外部事件/中断的区别及EXTI->SWIER的用途

    EXTI_SWIER作用:允许我们通过程序控制就可以启动中断/事件线 1.产生事件的线路最终的产物是一个脉冲信号,这个脉冲信号可以给其他外设电路使用,比如定时器TIM.模拟数字转换器ADC等等. 2. ...

  7. P2463 [SDOI2008]Sandy的卡片

    写一种\(O(nm)\)的做法,也就是\(O(\sum 串长)\)的. 先通过差分转化,把每个数变成这个数与上一个数的差,第一个数去掉,答案就是最长公共子串+1 按照套路把所有串拼起来,中间加一个分隔 ...

  8. Redis数据备份、安全、管理服务器笔记

    Redis 数据备份与恢复 Redis SAVE 命令用于创建当前数据库的备份. 实例 redis > SAVE OK 恢复数据 如果需要恢复数据,只需将备份文件 (dump.rdb) 移动到 ...

  9. 9、Dockerfile实战-Nginx

    上一节我们详解Dockerfile之后,现在来进行实战.我们通过docker build来进行镜像制作. build有如下选项: [root@localhost ~a]# docker build - ...

  10. 你应该知道Go语言的几个优势

    要说起GO语言的优势,我们就得从GO语言的历史讲起了-- 本文由腾讯技术工程官方号发表在腾讯云+社区 2007年,受够了C++煎熬的Google首席软件工程师Rob Pike纠集Robert Grie ...