DLX 舞蹈链 精确覆盖 与 重复覆盖
精确覆盖问题:给定一个由0-1组成的矩阵,是否能找到一个行的集合,使得集合中每一列都恰好包含一个1
还有重复覆盖问题
dancing links 是 一种数据结构,用来优化搜索,不算是一种算法。(双向循环十字链表)
参阅了白书训练指南上的模版,目前只有精确覆盖,等再补上重复覆盖
struct DLX
{
int n , sz; // 行数,节点总数
int S[maxn]; // 各列节点总数
int row[maxnode],col[maxnode]; // 各节点行列编号
int L[maxnode],R[maxnode],U[maxnode],D[maxnode]; // 十字链表 int ansd,ans[maxn]; // 解 void init(int n )
{
this->n = n ;
for(int i = ; i <= n; i++ )
{
U[i] = i ;
D[i] = i ;
L[i] = i - ;
R[i] = i + ;
}
R[n] = ;
L[] = n;
sz = n + ;
memset(S,,sizeof(S));
}
void addRow(int r,vector<int> c1)
{
int first = sz;
for(int i = ; i < c1.size(); i++ ){
int c = c1[i];
L[sz] = sz - ; R[sz] = sz + ; D[sz] = c ; U[sz] = U[c];
D[U[c]] = sz; U[c] = sz;
row[sz] = r; col[sz] = c;
S[c] ++ ; sz ++ ;
}
R[sz - ] = first ; L[first] = sz - ;
}
// 顺着链表A,遍历除s外的其他元素
#define FOR(i,A,s) for(int i = A[s]; i != s ; i = A[i]) void remove(int c){
L[R[c]] = L[c];
R[L[c]] = R[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) {++S[col[j]];U[D[j]] = j;D[U[j]] = j; }
L[R[c]] = c;
R[L[c]] = c;
}
bool dfs(int d){
if(R[] == ){
ansd = d;
return true;
}
// 找S最小的列c
int c = R[] ;
FOR(i,R,) 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 + )) return true;
FOR(j,L,i) restore(col[j]);
}
restore(c); return false;
}
bool solve(vector<int> & v){
v.clear();
if(!dfs()) return false;
for(int i = ; i< ansd ;i ++ ) v.push_back(ans[i]);
return true;
}
}; DLX solver; int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
solver.init(m);
int c , x;
vector<int> c1;
for(int i = ; i<= n ; i ++ )
{
scanf("%d",&c);
c1.clear();
for(int j = ; j < c ; j ++ ){scanf("%d",&x);c1.push_back(x);}
solver.addRow(i,c1);
}
vector<int> ans;
bool flag ;
flag = solver.solve(ans);
if(flag )
{
int size1 = ans.size();
printf("%d",size1);
for(int i = ; i < size1;i ++ )
printf(" %d",ans[i]);
printf("\n");
}
else printf("NO\n");
}
return ;
}
DLX 精确覆盖 template
//明天再写。。。
重复覆盖与精确覆盖做法稍有不同
精确覆盖:
首先选择当前要覆盖的列(含1最少的列),将该列和能够覆盖到该列的行全部去掉,再枚举添加的方法。
枚举某一行r,假设它是解集中的一个,那么该行所能覆盖到的所有列都不必再搜,所以删除该行覆盖到的所有列,又由于去掉的列相当于有解,所以能够覆盖到这些列的行也不用再搜,删之。
重复覆盖:
首先选择当前要覆盖的列(同上),将该列删除,枚举覆盖到该列的所有行:对于某一行r,假设它是解集中的一个,那么该行所能覆盖到的列都不必再搜,所以删除该行覆盖到的所有列。
注意此时不用删去覆盖到这些列的行,因为一列中允许有多个1。
这里有一个A*的优化:估价函数h意义为从当前状态最好情况下需要添加几条边才能覆盖。
const int maxn=;
const int maxc=;
const int maxr=;
const int inf=0x3f3f3f3f;
int L[maxn], R[maxn], D[maxn], U[maxn], C[maxn];
int S[maxc], H[maxr], size;
///不需要S域
void Link(int r, int c)
{
S[c]++; C[size]=c;
U[size]=U[c]; D[U[c]]=size;
D[size]=c; U[c]=size;
if(H[r]==-) H[r]=L[size]=R[size]=size;
else {
L[size]=L[H[r]]; R[L[H[r]]]=size;
R[size]=H[r]; L[H[r]]=size;
}
size++;
}
void remove(int c){
for (int i=D[c]; i!=c; i=D[i])
L[R[i]]=L[i], R[L[i]]=R[i];
}
void resume(int c){
for (int i=U[c]; i!=c; i=U[i])
L[R[i]]=R[L[i]]=i;
}
int h(){///用精确覆盖去估算剪枝
int ret=;
bool vis[maxc];
memset (vis, false, sizeof(vis));
for (int i=R[]; i; i=R[i])
{
if(vis[i])continue;
ret++;
vis[i]=true;
for (int j=D[i]; j!=i; j=D[j])
for (int k=R[j]; k!=j; k=R[k])
vis[C[k]]=true;
}
return ret;
} int ans;
void Dance(int k){ //根据具体问题选择限制搜索深度或直接求解。
if(k+h()>=ans) return;
if(!R[]){
if(k<ans)ans=k;
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]){
remove(i);
for (int j=R[i]; j!=i; j=R[j])
remove(j);
Dance(k+);
for (int j=L[i]; j!=i; j=L[j])
resume(j);
resume(i);
}
return ;
} void initL(int x){///col is 1~x,row start from 1
for (int i=; i<=x; ++i){
S[i]=;
D[i]=U[i]=i;
L[i+]=i; R[i]=i+;
}///对列表头初始化
R[x]=;
size=x+;///真正的元素从m+1开始
memset (H, -, sizeof(H));
///mark每个位置的名字
}
DLX 重复覆盖 template
做了6个题:poj2074 poj3076 前者是9阶数独,后者是16阶数独,以16阶为例,把问题转化为矩阵,总共有16*16*4列,(行、列、小宫格、每个位置)。有16*16*16行。
hust1017 直接给出了精确覆盖问题的定义和模型。不用建模了,直接把输入建成矩阵即可。
zoj3209 矩阵覆盖,行数就是矩阵数,列数为要覆盖的大矩阵的格子数目(化为格子,输入的小矩阵也化为格子后一列就可以出来了)
上面都是精确覆盖,白书训练指南上的模版用的很舒心。
然后我想重复覆盖把这个模版改一改就好吧,结果
FZU 1686 这个题,用改出来的模版死活不过,一直超时,我觉着没啥问题了还是不过。直接去找了另外的模版。另外的题都用了
这题是告诉n*m的格子上有许多1(怪物),然后每次可以消灭(连续的)n1*m1格子内的怪物,问最少几次把所有怪物消灭掉,枚举所有的攻击方案,为行数,列数为1的个数
hdu2295 给定n个城市,m个地点可以建造雷达,最多建k个雷达,问雷达的最小覆盖半径为多少。二分枚举覆盖半径,用重复覆盖判定可否选k个以内的雷达覆盖完所有的城市。行数即为雷达个数,列为城市个数,1为每个雷达可以覆盖到的城市的。这个题目我用的上面的重复覆盖的模版,先把答案求出来然后在判定结果,结果一直超时+wa,之后改为直接在dance的时候限制搜索深度为k就AC了。错了好多次,中间hdu坏了2次,好无奈。。。。
DLX 舞蹈链 精确覆盖 与 重复覆盖的更多相关文章
- DLX精确覆盖与重复覆盖模板题
hihoCoder #1317 : 搜索四·跳舞链 原题地址:http://hihocoder.com/problemset/problem/1317 时间限制:10000ms 单点时限:1000ms ...
- SPOJ 1771&&DLX精确覆盖,重复覆盖
DLX的题,做过这题才算是会吧. 这道题转化成了精确覆盖模型来做,一开始,只是单纯的要覆盖完行列和斜线,WA. 后来醒悟了,不能这样,只要覆盖全部行或列即可.虽然如此,但某些细节地方很关键不能考虑到. ...
- DLX舞蹈链 hdu5046
题意: 在N个城市选出K个城市,建飞机场(1 ≤ N ≤ 60,1 ≤ K ≤ N),N个城市给出坐标,选择这K个机场,使得从城市到距离自己最近的机场的 最大的距离 最小. 输出这个最小值. 思路: ...
- HDU 3957 Street Fighter (最小支配集 DLX 重复覆盖+精确覆盖 )
DLX经典题型,被虐惨了…… 建一个2*N行3*N列的矩阵,行代表选择,列代表约束.前2*N列代表每个人的哪种状态,后N列保证每个人至多选一次. 显然对手可以被战胜多次(重复覆盖),每个角色至多选择一 ...
- 舞蹈链(DLX)
舞蹈链(DLX) Tags:搜索 作业部落 评论地址 一.概述 特别特别感谢这位童鞋His blog 舞蹈链是一种优美的搜索,就像下面这样跳舞- 舞蹈链用于解决精确覆盖或者重复覆盖的问题 你可以想象成 ...
- HDU 2295 Radar dancing links 重复覆盖
就是dancing links 求最小支配集,重复覆盖 精确覆盖时:每次缓存数据的时候,既删除行又删除列(这里的删除列,只是删除表头) 重复覆盖的时候:只删除列,因为可以重复覆盖 然后重复覆盖有一个估 ...
- [poj3074]Sudoku(舞蹈链)
题目链接:http://poj.org/problem?id=3074 舞蹈链精确覆盖的经典题目,一个数独每个位置的要求,可以得到以下四个约束1.每个位置有且只有一个数字2.每个位置的数字在一行只能出 ...
- 跳跃的舞者,舞蹈链(Dancing Links)算法——求解精确覆盖问题
精确覆盖问题的定义:给定一个由0-1组成的矩阵,是否能找到一个行的集合,使得集合中每一列都恰好包含一个1 例如:如下的矩阵 就包含了这样一个集合(第1.4.5行) 如何利用给定的矩阵求出相应的行的集合 ...
- [转] 舞蹈链(Dancing Links)——求解精确覆盖问题
转载自:http://www.cnblogs.com/grenet/p/3145800.html 精确覆盖问题的定义:给定一个由0-1组成的矩阵,是否能找到一个行的集合,使得集合中每一列都恰好包含一个 ...
随机推荐
- 使用C++名单在文档处理和学生成绩管理系统相结合
对于学生成绩管理系统,我并不陌生,几乎学习C人的语言.做项目会想到学生成绩管理系统,我也不例外.在研究中的一段时间C语言之后,还用C语言到学生管理系统,然后做几个链接.计数,这个系统是以前的系统上的改 ...
- 解决tomcat开始出现in production environments was not found on the java.library.path:xxx
如图所看到的,Eclipse中启动tomcat时出现not found on the java.library.path等信息.能够通过下载tomcat-native-1.1.32-win32-bin ...
- RPC模式的Hub操作
signalR 专题—— 第四篇 模拟RPC模式的Hub操作 在之前的文章中,我们使用的都是持久连接,但是使用持久连接的话,这种模拟socket的形式使用起来还是很不方便的,比如只有一个唯一的 O ...
- C该程序生成一个唯一的序列号
在实际的软件开发项目,通常,它包括产生一唯一的序列号.在本文中,一个切实可行的方案,例如,它引入了一个唯一的序列号生成过程. 本文生成的序列号的样式为:MMDDHHMINSS_XXXXXX. 程序例如 ...
- JavaScript 常见陷阱
JavaScript中的一些特性和通常我们想象的不太一样.这里我总结了一些有悖直觉的语言特性. 1 数组 1.1 数组的遍历 在直接支持for a in b的语言中,比方Python/Ruby里的a的 ...
- 基于Cocos2dx开发卡牌游戏_松开,这三个国家
1.它实现了动态读取地图资源.地图信息被记录excel桌格.假设你想添加地图,编者excel导入后CocoStudio数据编辑器,然后出口到Json档,到项目的Resource文件夹下. 2.SGFi ...
- React Native环境配置
React Native环境配置 史上最全Windows版本搭建安装React Native环境配置 配置过React Native 环境的都知道,在Windows React Native环境配置有 ...
- Linux 0.12 内核管理存储器
Linux 0.12 内核管理存储器 其分段,用分段的机制把进程间的虚拟地址分隔开. 每一个进程都有一张段表LDT.整个系统有一张GDT表.且整个系统仅仅有一个总页表. 其地址翻译过程为: 程序中给出 ...
- 判断闰年(go语言版本)
import "strconv" func IsLeapYear(y string) bool { //y == 2000, 2004 //判断是否为闰年 year, _ := s ...
- xshell联系CentOS6.5 iptables要么ls 乱码输出
今天Xshell 联系CentOS6.5.当终端>编码设置为:Unicode(UTF-8)时刻,跑service iptables restart输出是乱码命令:当编码被设置为:当默认语言.ls ...