poj 3740 Easy Finding 二进制压缩枚举dfs 与 DLX模板详细解析
题目链接:http://poj.org/problem?id=3740
题意: 是否从0,1矩阵中选出若干行,使得新的矩阵每一列有且仅有一个1?
原矩阵N*M $ 1<= N <= 16 $ , $ 1 <= M <= 300$
解法1:由于行数不多,二进制枚举选出的行数,时间复杂度为O((1<<16)*K), 其中K即为判断选出的行数是否存在相同的列中有重复的1;
优化:将1状压即可,这样300的列值,压缩在int的32位中,使得列数“好像”小于10了;这样每次只需要 一个数 进行与运算,即可判断32个列是否有重复的1;使得K <= 10;
并且在选中一列和删除一列时, 两次 xor操作就可复原~~
47ms ~~
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std; const int bit = ;
const int L = ;
int n, m, x[][L], g[L], w[L];
bool check(int *x, int *w)
{
for(int i = ; i < L; i++){
if(x[i] & w[i]) return true;
}
return false;
}
bool dfs(int p)
{
int flag = ;
for(int i = ; i < L && flag; i++) if(g[i] != w[i]) flag = ;
if(flag) return true;
if(p == n) return false;
if(check(x[p], w)) return dfs(p + ); // 判断是否当前的列与之前选中的列有重复的1 for(int i = ; i < L; i++) w[i] ^= x[p][i];
if(dfs(p+)) return true;
for(int i = ; i < L; i++) w[i] ^= x[p][i]; // 不选当前的列
return dfs(p+);
}
int main()
{
char a;
while( scanf("%d%d", &n, &m) == ){
memset(x, , sizeof(x));
for(int i = ; i < n; i++){
for(int j = ; j < m; j++){
a = getchar();
while (!isdigit(a)) a = getchar();
if (a == '') x[i][j/bit] |= << j%bit;
}
}
memset(w, , sizeof(w));
memset(g, , sizeof(g));
for(int i = ; i < m; i++) g[i/bit] |= << i%bit; if(dfs()) puts("Yes, I found it");
else puts("It is impossible");
}
}
解法2: DLX模板题,初学DLX,下面写下理解:
在DLX中搞清楚几个函数的含义,以及删除和恢复列操作的含义基本上理解了DLX 的模板了;
C[i] 表示每个有效节点所在的列, S[i] 表示每一列有效节点的个数,H[i] 表示每一列最右边有效节点的的标号;
L[i], R[i], U[i], D[i] 分别表示有效节点 i 上下左右节点的标号;
其中U[c] (c为列的标号) 表示列c中最下面的有效节点的标号, D[c] (c为列的标号)表示列c中最上面的有效节点的标号;
并且在删除和恢复一列时,循环遍历的是该列中的每一个节点; 这和选中一列,之后删除/恢复 行不同, 删除/恢复 行并没有包括起点(起点在列中操作了);
具体的DLX思路: 选出S中最小的列c, 删除列c中所有的有效节点所在的行,之后枚举选出的是哪行;再删除该行所有有效节点所在的列;递归求解即可;
63ms ... 进竟然没有压缩枚举快,,写挫了
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define inf 0x3f3f3f3f
const int maxn = ;
int tot, head, n, m;
int C[maxn], S[maxn], H[maxn];
int U[maxn], D[maxn], L[maxn], R[maxn];
inline void add_link(int i, int j)
{
C[++tot] = j;
S[j]++; D[tot] = j;
U[tot] = U[j];
D[U[tot]] = tot;
U[D[tot]] = tot;//U[j]表示第j列最下面节点标号; if(H[i]) L[tot] = H[i], R[tot] = R[H[i]]; // H[i]是第i行最右边的节点标号
else R[tot] = L[tot] = tot; R[L[tot]] = tot;
L[R[tot]] = tot;
H[i] = tot;
} void Remove(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]){
U[D[j]] = U[j];
D[U[j]] = D[j];
S[C[j]]--;
}
}
} void Resume(int c)
{
for(int i = U[c]; i != c; i = U[i]){
for(int j = L[i]; j != i; j = L[j]){
U[D[j]] = j;
D[U[j]] = j;
S[C[j]]++;
}
}
R[L[c]] = c; L[R[c]] = c;
}
bool DLX()
{
if(R[head] == head) return true;
int c, mn = inf;
for(int i = R[head]; i != head; i = R[i]) if(mn > S[i]) c = i, mn = S[i]; Remove(c);
for(int i = D[c]; i != c; i = D[i]){
for(int j = R[i]; j != i; j = R[j]) Remove(C[j]); if(DLX()) return true;
for(int j = L[i]; j != i; j = L[j]) Resume(C[j]);
}
Resume(c); return false;
}
int main()
{
while( scanf("%d%d", &n, &m) == ){
tot = m; head = ;
for(int i = ; i <= m; i++){
C[i] = U[i] = D[i] = i;
L[i+] = i;
R[i] = i+;
S[i] = ;
}
L[] = m, R[m] = ; char x;
for(int i = ; i <= n; i++){
H[i] = ;
for(int j = ; j <= m; j++){
x = getchar();
while (!isdigit(x)) x = getchar();
if (x == '') add_link(i, j);
}
}
if(DLX()) puts("Yes, I found it");
else puts("It is impossible");
}
}
poj 3740 Easy Finding 二进制压缩枚举dfs 与 DLX模板详细解析的更多相关文章
- poj 3740 Easy Finding(Dancing Links)
Easy Finding Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 15668 Accepted: 4163 Des ...
- [ACM] POJ 3740 Easy Finding (DLX模板题)
Easy Finding Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 16178 Accepted: 4343 Des ...
- [ACM] POJ 3740 Easy Finding (DFS)
Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 16202 Accepted: 4349 Description Give ...
- poj 3740 Easy Finding 精确匹配
题目链接 dlx的第一题, 真是坎坷..... #include <iostream> #include <vector> #include <cstdio> #i ...
- POJ 3740 Easy Finding
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using ...
- Easy Finding POJ - 3740 (DLX)
显然这是一道dfs简单题 或许匹配也能做 然而用了dancing links 显然这也是一道模板题 好的吧 调了一上午 终于弄好了模板 Easy Finding Time Limit: 1000MS ...
- POJ 2965 The Pilots Brothers' refrigerator【枚举+dfs】
题目:http://poj.org/problem?id=2965 来源:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=26732#pro ...
- codeforces B - Preparing Olympiad(dfs或者状态压缩枚举)
B. Preparing Olympiad You have n problems. You have estimated the difficulty of the i-th one as inte ...
- UVA 1508 - Equipment 状态压缩 枚举子集 dfs
UVA 1508 - Equipment 状态压缩 枚举子集 dfs ACM 题目地址:option=com_onlinejudge&Itemid=8&category=457& ...
随机推荐
- Java协变返回类型
今天看到句话:“支持重写方法时返回协变类型”. 那么什么事协变类型?在网上找了找资料,大体上明白了. Java 5.0添加了对协变返回类型的支持,即子类覆盖(即重写)基类方法时,返回的类型可以是基类方 ...
- 索引与优化like查询
1. like %keyword 索引失效,使用全表扫描.但可以通过翻转函数+like前模糊查询+建立翻转函数索引=走翻转函数索引,不走全表扫描. 2. like keyword% 索引有 ...
- Linux命令之cut
cut:文件的每一行剪切字节.字符和字段并将这些字节.字符和字段写至标准输出.如果不指定 File 参数,cut 命令将读取标准输入.必须指定 -b.-c 或 -f 标志之一. 主要参数: -b(by ...
- IIs站点的建立
控制面板——管理工具——Internet信息服务管理器 首先应设置的文件权限:System 和 admin 程序池:4.0 编辑权限:iis apppool\名称 身份验证:匿名身份——应用程序池标识
- Unity之屏幕画线
using UnityEngine;using System.Collections; public class DrawRectangle : MonoBehaviour { public Colo ...
- CSS标签知识
一.内联标签和块标签的区别 内联,内嵌,行内属性标签: 1.默认同行可以继续跟同类型标签: 2.内容撑开宽度 3.不支持宽高 4.不支持上下的margin和padding 5.代码换行被解析 块属性标 ...
- shell运行报 too many arguments错误
有时候shell在运行的时候可能会报 too many arguments错误,出现这种错误的一般情况是出现了多值问题,也就是一个变量可能有多个值了. 例:#!/bin/sh echo "I ...
- jquery设置div,文本框 表单的值示例
我们将使用前一章中的三个相同的方法来设置内容: text() - 设置或返回所选元素的文本内容html() - 设置或返回所选元素的内容(包括 HTML标记)val() - 设置或返回表单字段的值 1 ...
- 二叉树-你必须要懂!(二叉树相关算法实现-iOS)
这几天详细了解了下二叉树的相关算法,原因是看了唐boy的一篇博客(你会翻转二叉树吗?),还有一篇关于百度的校园招聘面试经历,深刻体会到二叉树的重要性.于是乎,从网上收集并整理了一些关于二叉树的资料,及 ...
- 杭电ACM2091--空心三角形
http://acm.hdu.edu.cn/showproblem.php?pid=2091 scanf 和 printf的输入输出功能并不强大.有时候我们需要清空输入输出流,所以一定切记getcha ...