DLX精确覆盖与重复覆盖模板题
hihoCoder #1317 : 搜索四·跳舞链
原题地址:http://hihocoder.com/problemset/problem/1317
时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
小Ho最近遇到一个难题,他需要破解一个棋局。
棋局分成了n行,m列,每行有若干个棋子。小Ho需要从中选择若干行使得每一列有且恰好只有一个棋子。
比如下面这样局面:
其中1表示放置有棋子的格子,0表示没有放置棋子。
对于上面这个问题,小Ho经过多次尝试以后得到了解为选择2、3、4行就可以做到。
但是小Ho觉得自己的方法不是太好,于是他求助于小Hi。
小Hi:小Ho你是怎么做的呢?
小Ho:我想每一行都只有两种状态,选中和未被选中。那么我将选中视为1,未选中视为0。则每一种组合恰好对应了一个4位的01串,也就是一个4位的二进制数。
小Hi:恩,没错。
小Ho:然后我所做的就是去枚举每一个二进制数然后再来判定是否满足条件。
小Hi:小Ho你这个做法本身没什么问题,但是对于棋盘行数再多一点的情况就不行了。
小Ho:恩,我也这么觉得,那你有什么好方法么?
小Hi:我当然有了,你听我慢慢道来。
输入
第1行:1个正整数t,表示数据组数,1≤t≤10。
接下来t组数据,每组的格式为:
第1行:2个正整数n,m,表示输入数据的行数和列数。2≤n,m≤100。
第2..n+1行:每行m个数,只会出现0或1。
输出
第1..t行:第i行表示第i组数据是否存在解,若存在输出"Yes",否则输出"No"。
样例输入
2
4 4
1 1 0 1
0 1 1 0
1 0 0 0
0 1 0 1
4 4
1 0 1 0
0 1 0 0
1 0 0 0
0 0 1 1
样例输出
No
Yes
DLX精确覆盖
#include <algorithm>
#include <cstring>
#include <string.h>
#include <iostream>
#include <list>
#include <map>
#include <set>
#include <stack>
#include <string>
#include <utility>
#include <queue>
#include <vector>
#include <cstdio>
#include <cmath> #define LL long long using namespace std; const int maxnode = ; //最多多少个‘1’
const int MaxM = ;
const int MaxN = ; struct DLX
{
int n,m,SIZE;
int U[maxnode],D[maxnode],R[maxnode],L[maxnode],Row[maxnode],Col[maxnode];//L,R,D,U四个数组记录某节点上下左右邻居
int H[MaxN], S[MaxM];//H记录排头,S记录某列有多少个节点
int ansd, ans[MaxN];
void init(int _n,int _m)
{
n = _n;
m = _m;
for(int i = ;i <= m;i++)
{
S[i] = ;
U[i] = D[i] = i;
L[i] = i-;
R[i] = i+;
}
R[m] = ; L[] = m;
SIZE = m;
for(int i = ;i <= n;i++)
H[i] = -;
}
void Link(int r,int c)
{
++S[Col[++SIZE]=c];
Row[SIZE] = r;
D[SIZE] = D[c];
U[D[c]] = SIZE;
U[SIZE] = c;
D[c] = SIZE;
if(H[r] < )H[r] = L[SIZE] = R[SIZE] = SIZE;
else
{
R[SIZE] = R[H[r]];
L[R[H[r]]] = SIZE;
L[SIZE] = H[r];
R[H[r]] = SIZE;
}
}
void exact_Remove(int c)
{
L[R[c]] = L[c]; R[L[c]] = R[c];
for(int i = D[c];i != c;i = D[i])
for(int j = R[i];j != i;j = R[j])
{
U[D[j]] = U[j];
D[U[j]] = D[j];
--S[Col[j]];
}
}
void repeat_remove(int c) {
for(int i = D[c]; i != c; i = D[i])
L[R[i]] = L[i], R[L[i]] = R[i];
}
void repeat_resume(int c) {
for(int i = U[c]; i != c; i = U[i])
L[R[i]] = R[L[i]] = i;
} int f() { //估价函数。
bool vv[MaxM];
int ret = , c, i, j;
for(c = R[]; c != ; c = R[c]) vv[c] = ;
for(c = R[]; c != ; c = R[c])
if(vv[c]) {
++ret, vv[c] = ;
for(i = D[c]; i != c; i = D[i])
for(j = R[i]; j != i; j = R[j])
vv[Col[j]] = ;
}
return ret;
} void repeat_dance(int d) {
if(d + f() >= ansd) return; //估价函数剪枝,A*搜索
if(R[] == ) {
if(d < ansd) ansd = d;
return;
}
int c = R[], i, j;
for(i = R[]; i; i = R[i])
if(S[i] < S[c]) c = i;
for(i = D[c]; i != c; i = D[i]) {
repeat_remove(i);
for(j = R[i]; j != i; j = R[j]) repeat_remove(j);
repeat_dance(d + );
for(j = L[i]; j != i; j = L[j]) repeat_resume(j);
repeat_resume(i);
}
}
void exact_resume(int c)
{
for(int i = U[c];i != c;i = U[i])
for(int j = L[i];j != i;j = L[j])
++S[Col[U[D[j]]=D[U[j]]=j]];
L[R[c]] = R[L[c]] = c;
}
//d为递归深度
bool exact_Dance(int d)
{
if(R[] == )
{
ansd = d;
return true;
}
int c = R[];
for(int i = R[];i != ;i = R[i])
if(S[i] < S[c])
c = i;
exact_Remove(c);
for(int i = D[c];i != c;i = D[i])
{
ans[d] = Row[i];
for(int j = R[i]; j != i;j = R[j]) exact_Remove(Col[j]);
if(exact_Dance(d+))return true;
for(int j = L[i]; j != i;j = L[j]) exact_resume(Col[j]);
}
exact_resume(c);
return false;
}
}; DLX g;
int main()
{
int n,m;
int t;
cin>>t; while( t--)
{
scanf("%d%d",&n,&m);
g.init(n,m);
for(int i = ;i <= n;i++)
{
int num;
for(int j=;j<=m;j++)
{
scanf("%d",&num);
if(num==) g.Link(i,j);
}
}
if(!g.exact_Dance())printf("No\n");
else
printf("Yes\n");
}
return ;
}
HDU 3498 whosyourdaddy
http://acm.hdu.edu.cn/showproblem.php?pid=3498
whosyourdaddyTime Limit: 20000/10000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Problem sevenzero Input There Output One Sample 5 4 1 2 1 3 2 4 4 5 6 4 1 2 1 3 1 4 4 5 Sample Output 2 3 Author sevenzero Source 2010 ACM-ICPC Multi-University Training Contest(7)——Host by HIT |
DLX重复覆盖
n个敌对单元,m对单元互相相邻,建图的邻接矩阵,DLX。
#include <algorithm>
#include <cstring>
#include <string.h>
#include <iostream>
#include <list>
#include <map>
#include <set>
#include <stack>
#include <string>
#include <utility>
#include <queue>
#include <vector>
#include <cstdio>
#include <cmath> #define LL long long using namespace std; const int maxnode = ; //最多多少个1
const int MaxM = ;
const int MaxN = ; struct DLX
{
int n,m,SIZE;
int U[maxnode],D[maxnode],R[maxnode],L[maxnode],Row[maxnode],Col[maxnode];//L,R,D,U四个数组记录某节点上下左右邻居
int H[MaxN], S[MaxM];//H记录行头,S记录某列有多少个节点
int ansd, ans[MaxN];
void init(int _n,int _m)
{
n = _n;
m = _m;
for(int i = ;i <= m;i++)
{
S[i] = ;
U[i] = D[i] = i;
L[i] = i-;
R[i] = i+;
}
R[m] = ; L[] = m;
SIZE = m;
for(int i = ;i <= n;i++)
H[i] = -;
}
void Link(int r,int c)
{
++S[Col[++SIZE]=c];
Row[SIZE] = r;
D[SIZE] = D[c];
U[D[c]] = SIZE;
U[SIZE] = c;
D[c] = SIZE;
if(H[r] < )H[r] = L[SIZE] = R[SIZE] = SIZE;
else
{
R[SIZE] = R[H[r]];
L[R[H[r]]] = SIZE;
L[SIZE] = H[r];
R[H[r]] = SIZE;
}
}
void exact_Remove(int c)
{
L[R[c]] = L[c]; R[L[c]] = R[c];
for(int i = D[c];i != c;i = D[i])
for(int j = R[i];j != i;j = R[j])
{
U[D[j]] = U[j];
D[U[j]] = D[j];
--S[Col[j]];
}
}
void repeat_remove(int c) {
for(int i = D[c]; i != c; i = D[i])
L[R[i]] = L[i], R[L[i]] = R[i];
}
void repeat_resume(int c) {
for(int i = U[c]; i != c; i = U[i])
L[R[i]] = R[L[i]] = i;
} int f() { //估价函数。
bool vv[MaxM];
int ret = , c, i, j;
for(c = R[]; c != ; c = R[c]) vv[c] = ;
for(c = R[]; c != ; c = R[c])
if(vv[c]) {
++ret, vv[c] = ;
for(i = D[c]; i != c; i = D[i])
for(j = R[i]; j != i; j = R[j])
vv[Col[j]] = ;
}
return ret;
} void repeat_dance(int d) {
if(d + f() >= ansd) return; //估价函数剪枝,A*搜索
if(R[] == ) {
if(d < ansd) ansd = d;
return;
}
int c = R[], i, j;
for(i = R[]; i; i = R[i])
if(S[i] < S[c]) c = i;
for(i = D[c]; i != c; i = D[i]) {
repeat_remove(i);
for(j = R[i]; j != i; j = R[j]) repeat_remove(j);
repeat_dance(d + );
for(j = L[i]; j != i; j = L[j]) repeat_resume(j);
repeat_resume(i);
}
}
void exact_resume(int c)
{
for(int i = U[c];i != c;i = U[i])
for(int j = L[i];j != i;j = L[j])
++S[Col[U[D[j]]=D[U[j]]=j]];
L[R[c]] = R[L[c]] = c;
}
//d为递归深度
bool exact_Dance(int d)
{
if(R[] == )
{
ansd = d;
return true;
}
int c = R[];
for(int i = R[];i != ;i = R[i])
if(S[i] < S[c])
c = i;
exact_Remove(c);
for(int i = D[c];i != c;i = D[i])
{
ans[d] = Row[i];
for(int j = R[i]; j != i;j = R[j]) exact_Remove(Col[j]);
if(exact_Dance(d+))return true;
for(int j = L[i]; j != i;j = L[j]) exact_resume(Col[j]);
}
exact_resume(c);
return false;
}
}; DLX dlx;
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
dlx.init(n,n);
while(m--)
{
int a,b;
scanf("%d%d",&a,&b);
dlx.Link(a,b);
dlx.Link(b,a);
}
for(int i=;i<=n;i++)dlx.Link(i,i);
dlx.ansd=0x3f3f3f;
dlx.repeat_dance();
printf("%d\n",dlx.ansd);
}
return ;
}
DLX精确覆盖与重复覆盖模板题的更多相关文章
- SPOJ 1771&&DLX精确覆盖,重复覆盖
DLX的题,做过这题才算是会吧. 这道题转化成了精确覆盖模型来做,一开始,只是单纯的要覆盖完行列和斜线,WA. 后来醒悟了,不能这样,只要覆盖全部行或列即可.虽然如此,但某些细节地方很关键不能考虑到. ...
- DLX 舞蹈链 精确覆盖 与 重复覆盖
精确覆盖问题:给定一个由0-1组成的矩阵,是否能找到一个行的集合,使得集合中每一列都恰好包含一个1 还有重复覆盖问题 dancing links 是 一种数据结构,用来优化搜索,不算是一种算法.(双向 ...
- HDU 3957 Street Fighter (最小支配集 DLX 重复覆盖+精确覆盖 )
DLX经典题型,被虐惨了…… 建一个2*N行3*N列的矩阵,行代表选择,列代表约束.前2*N列代表每个人的哪种状态,后N列保证每个人至多选一次. 显然对手可以被战胜多次(重复覆盖),每个角色至多选择一 ...
- HDU 2295 Radar dancing links 重复覆盖
就是dancing links 求最小支配集,重复覆盖 精确覆盖时:每次缓存数据的时候,既删除行又删除列(这里的删除列,只是删除表头) 重复覆盖的时候:只删除列,因为可以重复覆盖 然后重复覆盖有一个估 ...
- HDU 3957 Street Fighter(搜索、DLX、重复覆盖+精确覆盖)
很久以前就看到的一个经典题,一直没做,今天拿来练手.街霸 给n<=25个角色,每个角色有 1 or 2 个版本(可以理解为普通版以及爆发版),每个角色版本可以KO掉若干人. 问最少选多少个角色( ...
- 【转】DLX 精确覆盖 重复覆盖
问题描述: 给定一个n*m的矩阵,有些位置为1,有些位置为0.如果G[i][j]==1则说明i行可以覆盖j列. Problem: 1)选定最少的行,使得每列有且仅有一个1. 2)选定最少的行,使得每列 ...
- dancing link 精确覆盖 重复覆盖 (DLX)
申明:因为转载的没有给出转载链接,我就把他的链接附上,请尊重原创: http://www.cnblogs.com/-sunshine/p/3358922.html 如果谁知道原创链接 给一下,请尊重原 ...
- HDU 5046 Airport【DLX重复覆盖】
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5046 题意: 给定n个城市的坐标,要在城市中建k个飞机场,使城市距离最近的飞机场的最长距离最小,求这 ...
- (中等) HDU 3335 , DLX+重复覆盖。
Description As we know,the fzu AekdyCoin is famous of math,especially in the field of number theory. ...
随机推荐
- c# Http Post访问接口方式
一.json格式数据提交返回 提交和返回数据都为json格式 参数提交方式:application/json;charset=UTF-8 统一采用UTF-8字符编码 public string Pos ...
- ARP/RARP
IP地址和MAC地址之间的转换 点对点链路不使用ARP ARP高速缓存 ARP高效运行的关键是每个主机上都有一个ARP高速缓存. 存放了最近IP地址与MAC地址间的映射关系. 每一项生存时 ...
- ElasticSearch 监控单个节点详解
1.介绍 集群健康 就像是光谱的一端——对集群的所有信息进行高度概述. 而 节点统计值 API 则是在另一端.它提供一个让人眼花缭乱的统计数据的数组,包含集群的每一个节点统计值. 节点统计值 提供的统 ...
- python 小技巧(glob,guid,序列化,压缩字符,有序字典,sorted函数,分片)
1.glob模块 glob模块是最简单的模块之一,内容非常少.用它可以查找符合特定规则的文件路径名.跟使用windows下的文件搜索差不多.查找文件只用到三个匹配符:”*”, “?”, “[]”.”* ...
- SELinux的Docker安全性
原文译自:http://opensource.com/business/14/7/docker-security-selinux 这篇文章基于我今年在DockerCon一个讲座,它将讨论我们当前听到的 ...
- HTML5 Canvas 奔跑的小狗
效果如上图,共六个图像切换,形成小狗动态奔跑效果.完整代码和图片请从 https://files.cnblogs.com/files/xiandedanteng/runningDog.rar 下载. ...
- git学习——记录每次更新到仓库
记录每次更新到仓库 工作目录下面的所有文件都不外乎这两种状态:已跟踪或未跟踪.已跟踪的文件是指本来就被纳入版本控制管理的文件,在上次快照中有它们的记录,工作一段时间后,它们的状态可能是未更新,已修改或 ...
- DirectX 11游戏编程学习笔记之6: 第5章The Rendering Pipeline(渲染管线)
本文由哈利_蜘蛛侠原创,转载请注明出处.有问题欢迎联系2024958085@qq.com 注:我给的电子版是700多页,而实体书是800多页,所以我在提到相关概念的时候 ...
- Django的Form、CSRF、cookie和session
Django是一个大而全的web框架,为我们提供了很多实用的功能,本文主要介绍Form.CSRF.cookie和session 一.Form 在web页面中form表单是重要的组成部分,为了数据安全和 ...
- 计算两个有序数组的第K大数(转)
传统解法,最直观的解法是O(m+n).直接merge两个数组,然后求第K大的数字. 如果想要时间复杂度将为O(log(m+n)).我们可以考虑从K入手.如果我们每次能够删除一个一定在第K个元素之前的元 ...