[poj3074]Sudoku(舞蹈链)
题目链接:http://poj.org/problem?id=3074
舞蹈链精确覆盖的经典题目,一个数独每个位置的要求,可以得到以下四个约束
1.每个位置有且只有一个数字
2.每个位置的数字在一行只能出现一次
3.每个位置的数字在一列只能出现一次
4.每个位置的数字在一个宫格内只能出现一次
然后针对每个位置可以建立舞蹈链了
前81列,为1条件的约束
82-162列,为2条件的约束
163-243列,为3条件的约束
244-324列,为4条件的约束
则舞蹈链行数为确定的点数+未确定的点数*9,列数为324。
如果i行j列为数k,对应行则在(i - 1) 9 + j列,(i - 1) 9 + k + 81列, (j - 1) 9 + k + 162列,(((i - 1) / 3) 3 + ((j + 2) / 3) - 1)* 9 + k + 243列建立。
如果i行j列为未知数,则k为1-9,对于每个k都应该建立行列关系。
#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#include<string>
#include<algorithm>
#include<set>
#include<cstdlib>
#include<map>
#include<queue>
#include<cmath>
using namespace std;
typedef long long ll;
const int MN = ;
const int MM = ;
const int MNN = MN * MM + ;
struct DLX { int n, m, size;//一共n行m列,size个节点
int U[MNN], D[MNN], L[MNN], R[MNN], row[MNN], col[MNN];//第i个节点的上U下D左L右R,所在位置row行col列
int H[MNN], S[MM];//H数组记录行选择指针,S数组记录覆盖个数
int ansd, ans[MN];//res记录行个数,ans数组记录可行解
void init(int x, int y) {//初始化空表
n = x, m = y;
for (int i = ; i <= m; ++i) {//其中0节点作为head节点,其他作为列首节点
U[i] = D[i] = i;
L[i] = i - ;
R[i] = i + ;
}
R[m] = ; L[] = m;
size = m;
memset(S, , sizeof(S));
memset(H, -, sizeof(H));
}
void Link(int r, int c) {
size++; row[size] = r; col[size] = c; S[c]++;//节点数加一,设置s节点所处位置,以及S列覆盖个数加一
D[size] = D[c]; U[D[c]] = size;//将s节点插入对应列中
U[size] = c; D[c] = size;
if (H[r] < )//如果该行没有元素,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 remove(int c) {//删除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数组减一
--S[col[j]];
}
}
}
void resume(int c) {//恢复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[col[j]];
}
}
L[R[c]] = c; R[L[c]] = c;
}
bool dancing(int deep) {
if (R[] == ) {//当矩阵为空时,说明找到一个可行解,算法终止
ansd = deep;
return true;
}
int c = R[];//找到节点数最少的列,枚举这列上的所有行
for (int i = R[]; i != ; i = R[i]) {
if (S[i] < S[c]) {
c = i;
}
}
remove(c);//删除节点数最少的列
for (int i = D[c]; i != c; i = D[i]) {
ans[deep] = row[i];//将行r放入当前解
for (int j = R[i]; j != i; j = R[j])//行上节点对应的列上进行删除
remove(col[j]);
//进入下一层
if (dancing(deep + ))return true;
//对行上的节点对应的列进行恢复
for (int j = L[i]; j != i; j = L[j])
resume(col[j]);
}
//恢复节点数最少列
resume(c);
return false;
}
};
DLX dzl;
int mp[][];
int x[];
int y[];
int kk[];
int main() {
char s[];
while (cin >> s) {
if (strcmp(s, "end") == )
break;
for (int i = ; i < ; i++) {
int xx = i / ;
int yy = i % ;
if (s[i] == '.')
mp[xx + ][yy + ] = ;
else
mp[xx + ][yy + ] = s[i] - '';
}
dzl.init(, );
int len = ;
for (int i = ; i <= ; i++) {
for (int j = ; j <= ; j++) {
if (mp[i][j] == ) {
for (int k = ; k <= ; k++) {
dzl.Link(len, (i - ) * + j);
dzl.Link(len, (i - ) * + k + );
dzl.Link(len, (j - ) * + k + );
dzl.Link(len, (((i - ) / ) * + ((j + ) / ) - ) * + k + );
x[len] = i, y[len] = j, kk[len] = k;
len++;
}
}
else {
int k = mp[i][j];
dzl.Link(len, (i - ) * + j);
dzl.Link(len, (i - ) * + k + );
dzl.Link(len, (j - ) * + k + );
dzl.Link(len, (((i - ) / ) * + ((j + ) / ) - ) * + k + );
x[len] = i, y[len] = j, kk[len] = k;
len++;
}
}
}
dzl.dancing();
for (int i = ; i < dzl.ansd; i++) {
int r = dzl.ans[i];
mp[x[r]][y[r]] = kk[r];
}
for (int i = ; i <= ; i++) {
for (int j = ; j <= ; j++) {
printf("%d", mp[i][j]);
}
}
puts("");
}
}
[poj3074]Sudoku(舞蹈链)的更多相关文章
- POJ3074 Sudoku 舞蹈链 DLX
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目(传送门) 题意概括 给出一个残缺的数独,求解. 题解 DLX + 矩阵构建 (两个传送门) 代码 #include & ...
- POJ3076 Sudoku 舞蹈链 DLX
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目(传送门) 题意概括 给出一个残缺的16*16数独,求解. 题解 DLX + 矩阵构建 (两个传送门) 学完这个之后,再 ...
- POJ2676 Sudoku 舞蹈链 DLX
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目(传送门) 题意概括 给出一个残缺的数独,求解.SPJ 题解 DLX + 矩阵构建 (两个传送门) 代码 #includ ...
- 算法实践——舞蹈链(Dancing Links)算法求解数独
在“跳跃的舞者,舞蹈链(Dancing Links)算法——求解精确覆盖问题”一文中介绍了舞蹈链(Dancing Links)算法求解精确覆盖问题. 本文介绍该算法的实际运用,利用舞蹈链(Dancin ...
- 舞蹈链 DLX
欢迎访问——该文出处-博客园-zhouzhendong 去博客园看该文章--传送门 舞蹈链是一个非常玄学的东西…… 问题模型 精确覆盖问题:在一个01矩阵中,是否可以选出一些行的集合,使得在这些行的集 ...
- 转载 - 算法实践——舞蹈链(Dancing Links)算法求解数独
出处:http://www.cnblogs.com/grenet/p/3163550.html 在“跳跃的舞者,舞蹈链(Dancing Links)算法——求解精确覆盖问题”一文中介绍了舞蹈链(Dan ...
- 跳跃的舞者,舞蹈链(Dancing Links)算法——求解精确覆盖问题
精确覆盖问题的定义:给定一个由0-1组成的矩阵,是否能找到一个行的集合,使得集合中每一列都恰好包含一个1 例如:如下的矩阵 就包含了这样一个集合(第1.4.5行) 如何利用给定的矩阵求出相应的行的集合 ...
- DLX舞蹈链 hdu5046
题意: 在N个城市选出K个城市,建飞机场(1 ≤ N ≤ 60,1 ≤ K ≤ N),N个城市给出坐标,选择这K个机场,使得从城市到距离自己最近的机场的 最大的距离 最小. 输出这个最小值. 思路: ...
- [转] 舞蹈链(Dancing Links)——求解精确覆盖问题
转载自:http://www.cnblogs.com/grenet/p/3145800.html 精确覆盖问题的定义:给定一个由0-1组成的矩阵,是否能找到一个行的集合,使得集合中每一列都恰好包含一个 ...
随机推荐
- mysql中explain输出列之id的用法详解
参考mysql5.7 en manual,对列id的解释: The SELECT identifier. This is the sequential number of the SELECT wit ...
- Google Capture The Flag 2018 (Quals) - Reverse - Beginner's Quest - Gatekeeper
参考链接:https://ctftime.org/task/6264 题目 It's a media PC! All fully purchased through the online subscr ...
- BZOJ 1911 特别行动队 (斜率优化)
$ BZOJ~1911~*~ $ 特别行动队: (斜率优化) $ solution: $ 感觉这道题目还是比较常规的,首先我们很容易想到DP,因为题目里面说了选出的人都是连续的,这意味着我们可以从前往 ...
- linux下命令行执行Python程序提示no moudle,路径问题
在ide中执行python程序,已经设置好项目路径中. 但是在cmd中执行程序,所在路径是python的搜索路径,如果涉及到import引用就会报类似ImportError: No module na ...
- Python---基础---水仙花数和三色球
一.编写一个程序,求100~999之间的所有水仙花数 如果一个3位数等于其各位数字的立方和,则称这个数为水仙花数.例如:153 = 1^3 + 5^3 + 3^3,因此153就是一个水仙花数 for ...
- Linux g++ 编译添加 pthread
If you are going to compile a C program with pthread.h in LINUX using GCC or G++ you will have to us ...
- python 在不同CPU上同时运行多个程序
出处/From https://www.quora.com/If-you-run-Python-under-a-dual-core-CPU-then-can-you-run-two-Python-pr ...
- Linux命令行工具之pidstat命令
原创转载请注明出处:https://www.cnblogs.com/agilestyle/p/11484624.html pidstat命令就可以帮助我们监测到具体线程的上下文切换 通过pidstat ...
- Test 3.27 T1 立方体大作战
Description 一个叫做立方体大作战的游戏风靡整个 Byteotia.这个游戏的规则是相当复杂的,所以我们只介绍他的简单规则:给定玩家一个有 2n 个元素的栈,元素一个叠一个地放置.这些元 ...
- 微信公众号开发(二)获取access_token
参考:https://www.cnblogs.com/liuhongfeng/p/4848851.html 一:介绍. 接口调用请求说明 http请求方式: GET https://api.weixi ...