HDU 3111 Sudoku ( Dancing Links 精确覆盖模型 )
推荐两篇学DLX的博文:
http://bbs.9ria.com/thread-130295-1-1.html(这篇对DLX的工作过程演示的很详细)
http://yzmduncan.iteye.com/blog/1151695(这篇对精确覆盖与重复覆盖解释的简洁清晰,模板来自这篇博文)
以下转载:
DLX解决9*9的数独问题,转化为729*324的精确覆盖问题
行:一共9 * 9 * 9 == 729行。一共9 * 9小格,每一格有9种可能性(1 - 9),每一种可能都对应着一行。
列: 一共(9 + 9 + 9) * 9 + 81 == 324 种前面三个9分别代表着9行9列和9小块,乘以9的意思是9种可能(1 - 9),因为每种可能只可以选择一个。 81代表着81个小格,限制着每一个小格只放一个数字。
读入数据后,如果为'.',则建9行,即有1-9种可能,否则建一行,表示某小格只能放确定的某个数字。
以下个人理解:
列: 一共(9 + 9 + 9) * 9 + 81 == 324 种
对于这个(9+9+9)*9 我是这么理解的:一个数a,它在某一行有9个位置可以放,在某一列有9个位置可以放,在某一个3×3小格中有9个位置可以放,所以一共可以放的位置是(9+9+9)个,然后一共9个数字,所以是(9+9+9)*9 。
不知道这样理解是否正确,望大家指教!
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm> using namespace std; const int INF = << ;
const int SZ = ;
const int MAXR = SZ * SZ * SZ;
const int MAXC = ( SZ+SZ+SZ )*SZ + SZ*SZ; char mat[SZ+][SZ+];
char str[SZ+];
bool maxtri[MAXR+][MAXC+]; //01矩阵
int C[(MAXR+)*(MAXC+)], cnt[MAXC+];
int U[(MAXR+)*(MAXC+)], D[(MAXR+)*(MAXC+)];
int L[(MAXR+)*(MAXC+)], R[(MAXR+)*(MAXC+)];
int head;
int ans[MAXR+];
int val[SZ+][SZ+]; void Remove( int c )
{
int i, j;
L[ R[c] ] = L[c];
R[ L[c] ] = R[c];
for ( i = D[c]; i != c; i = D[i] )
{
for ( j = R[i]; j != i; j = R[j] )
{
U[ D[j] ] = U[j];
D[ U[j] ] = D[j];
--cnt[ C[j] ];
}
}
return;
} void Resume( int c )
{
int i, j;
R[ L[c] ] = c;
L[ R[c] ] = c;
for ( i = D[c]; i != c; i = D[i] )
{
for ( j = R[i]; j != i; j = R[j] )
{
U[ D[j] ] = j;
D[ U[j] ] = j;
++cnt[ C[j] ];
}
}
return;
} bool DFS( int cur )
{
int i, j, c, minv;
if ( R[head] == head )
return true; minv = INF;
for ( i = R[head]; i != head; i = R[i] )
{
if ( cnt[i] < minv )
{
minv = cnt[i];
c = i;
}
} Remove(c);
for ( i = D[c]; i != c; i = D[i] )
{
ans[cur] = (i - )/MAXC;
for( j = R[i]; j != i; j = R[j] )
Remove( C[j] ); if ( DFS( cur + ) ) return true; for( j = R[i]; j != i; j = R[j] )
Resume( C[j] );
} Resume(c);
return false;
} bool build()
{
int i, j, cur, pre, first;
head = ;
for ( i = ; i < MAXC; ++i )
{
R[i] = i + ;
L[i + ] = i;
}
R[ MAXC ] = ;
L[] = MAXC; //列双向链表
for ( j = ; j <= MAXC; ++j )
{
pre = j;
cnt[j] = ;
for ( i = ; i <= MAXR; ++i )
{
if ( maxtri[i][j] )
{
++cnt[j];
cur = i * MAXC + j; //当前节点的编号
C[cur] = j; //当前节点所在列
D[pre] = cur;
U[cur] = pre;
pre = cur;
}
}
U[j] = pre;
D[pre] = j;
if ( !cnt[j] ) return false; //一定无解
} //行双向链表
for ( i = ; i <= MAXR; ++i )
{
pre = first = -;
for ( j = ; j <= MAXC; ++j )
{
if( maxtri[i][j] )
{
cur = i * MAXC + j;
if ( pre == - ) first = cur;
else
{
R[pre] = cur;
L[cur] = pre;
}
pre = cur;
}
}
if ( first != - )
{
R[pre] = first;
L[first] = pre;
}
}
return true;
} /**************以上DLX模板*****************/ void show()
{
for ( int i = ; i <= MAXR; ++i )
{
for ( int j = ; j <= MAXC; ++j )
printf( "%d", maxtri[i][j] );
puts("");
}
return;
} //得到该情况下的01矩阵
void init()
{
memset( maxtri, false, sizeof(maxtri) ); for ( int i = ; i <= SZ; ++i )
{
for ( int j = ; j <= SZ; ++j )
{
int col = ( i - ) * SZ + j; //格子编号(1-81)
if ( mat[i][j] == '?' )
{
for ( int k = ; k <= SZ; ++k )
{
maxtri[ (col - )*SZ + k ][col] = true; //81保证不重复
maxtri[ (col - )*SZ + k ][ + (i - )*SZ + k ] = true; //9行中哪一行
maxtri[ (col - )*SZ + k ][ + (j - )*SZ + k ] = true; //9列中哪一列
maxtri[ (col - )*SZ + k ][ + ((i-)/* + (j-)/ )*SZ + k ] = true;//9小格中哪一个小格
}
}
else
{
int k = mat[i][j] - '';
maxtri[ (col - )*SZ + k ][col] = true;
maxtri[ (col - )*SZ + k ][ + (i - )*SZ + k ] = true;
maxtri[ (col - )*SZ + k ][ + (j - )*SZ + k ] = true;
maxtri[ (col - )*SZ + k ][ + ((i-)/* + (j-)/ )*SZ + k ] = true;
}
}
}
//show(); return;
} void PrintAns()
{
for ( int i = ; i < ; ++i )
{
int num = ans[i];
int gird = num / SZ;
if ( num % SZ ) ++gird;
int aaa = num % SZ;
if ( aaa == ) aaa = ;
int x = (gird-)/SZ+;
int y = (gird-)%SZ+;
val[x][y] = aaa;
} for ( int i = ; i <= SZ; ++i )
{
for ( int j = ; j <= SZ; ++j )
printf( "%d", val[i][j] );
puts("");
}
return;
} int main()
{
//freopen( "in.txt", "r", stdin );
//freopen( "out.txt", "w", stdout );
int T;
scanf( "%d", &T );
while ( T-- )
{
for ( int i = ; i <= SZ; ++i )
scanf( "%s", &mat[i][] );
if ( T ) scanf( "%s", str );
init();
if ( build() )
{
if ( DFS() )
PrintAns();
else puts("impossible");
}
else puts("impossible");
if ( T ) puts("---");
}
return ;
}
昨天比赛做到一个题,正解DLX,不过让薛薛位运算+剪枝直接暴过去了……跪。
为了保险起见,今天学了一下DLX。目前只明白了精确覆盖,对重复覆盖还不是很了解。
那个题似乎不是个很简单的DLX,需要精确覆盖+重复覆盖。orz,再接再厉吧。
不得不说,DLX的剪枝效果真是让人惊叹……
HDU 3111 Sudoku ( Dancing Links 精确覆盖模型 )的更多相关文章
- POJ3074 Sudoku —— Dancing Links 精确覆盖
题目链接:http://poj.org/problem?id=3074 Sudoku Time Limit: 1000MS Memory Limit: 65536K Total Submissio ...
- HDU 2295 Radar (二分 + Dancing Links 重复覆盖模型 )
以下转自 这里 : 最小支配集问题:二分枚举最小距离,判断可行性.可行性即重复覆盖模型,DLX解之. A*的启发函数: 对当前矩阵来说,选择一个未被控制的列,很明显该列最少需要1个行来控制,所以ans ...
- 【转】Dancing Links精确覆盖问题
原文链接:http://sqybi.com/works/dlxcn/ (只转载过来一部分,全文请看原文,感觉讲得很好~)正文 精确覆盖问题 解决精确覆盖问题 舞蹈步骤 效率分析 ...
- HDU 2295 Radar dancing links 重复覆盖
就是dancing links 求最小支配集,重复覆盖 精确覆盖时:每次缓存数据的时候,既删除行又删除列(这里的删除列,只是删除表头) 重复覆盖的时候:只删除列,因为可以重复覆盖 然后重复覆盖有一个估 ...
- hihoCoder #1321 : 搜索五•数独 (Dancing Links ,精确覆盖)
hiho一下第102周的题目. 原题地址:http://hihocoder.com/problemset/problem/1321 题意:输入一个9*9数独矩阵,0表示没填的空位,输出这个数独的答案. ...
- hust 1017 dancing links 精确覆盖模板题
最基础的dancing links的精确覆盖题目 #include <iostream> #include <cstring> #include <cstdio> ...
- ZOJ 3209 Treasure Map (Dancing Links 精确覆盖 )
题意 : 给你一个大小为 n * m 的矩形 , 坐标是( 0 , 0 ) ~ ( n , m ) .然后给你 p 个小矩形 . 坐标是( x1 , y1 ) ~ ( x2 , y2 ) , 你选 ...
- HDU 3335 Divisibility dancing links 重复覆盖
分析: dlx重复覆盖的巧用,重复覆盖的原理恰好符合本题的筛选方式,即选择一个数后,该数的倍数或约数可以保证在之后的搜索中不会被选择 于是修改一下启发函数,求解最大的重复覆盖即可. 其实不一定不被 ...
- HDU 5046 Airport ( Dancing Links 反复覆盖 )
今年上海网络赛的一道题目 , 跟 HDU 2295 如出一辙 . 就是距离的计算一个是欧几里得距离 , 一个是曼哈顿距离 学完DLX感觉这题好水 ,就是一个裸的反复覆盖 注意下别溢出即可了 #incl ...
随机推荐
- AVR446_Linear speed control of stepper motor步进电机曲线分析
1.1. 单片机代码处理 // 定义定时器预分频,定时器实际时钟频率为:72MHz/(STEPMOTOR_TIMx_PRESCALER+1) #define STEPMOTOR_TIM_PRESCA ...
- JavaEE权限管理系统的搭建(三)--------springmvc和mabatis整合环境搭建
本节介绍如何环境的搭建和配置: 首先要在父工程引入jar包依赖: <!-- 通过属性定义指定jar的版本 --> <properties> <spring.version ...
- Git基础篇
对于Git的一些基础了解,安装,里面的一些名词,这里就不做介绍了.主要记录怎么使用GIt. 本篇介绍: 配置个人信息 生成本地仓库并与远程库相连 添加SSH秘钥 ...
- socket传送二进制流的一些总结
第一次实质性的接触socket通信方面的工作,所以遇到的问题还真不少,写篇博客记录一下,提升下记忆. 需求是通过私有协议进行二进制数据的传输,必须保证数据包不能被丢失,所以选择tcp的socket进行 ...
- springBoot支持PageHelp插件使用学习笔记
首先在springboot项目的maven中加入依赖(版本可能需要自己选择合适的) <dependency> <groupId>com.github.pagehelper< ...
- 路由器基础配置之rip
我们将以上面的拓扑图进行实验,用rip协议来进行实验,目的是实现三台不同网段的pc机之间实现互相通信 首先为pc机配置好ip地址和网关,配置完IP地址后在配置路由器 router1: enable 进 ...
- linux下Tomcat配置提示权限不够解决办法
在终端输入命令 sudo chmod -R 777 /opt/Tomcat,那么Tomcat文件夹和它下面的所有子文件夹的属性都变成了777(读/写/执行权限)
- PHP ping
<?php /// start ping.inc.php /// $g_icmp_error = "No Error"; // timeout in ms function ...
- php扩展开发-资源类型
资源类型在内核中的结构 //zend_list.h typedef struct _zend_rsrc_list_entry { void *ptr; int type; int refcount; ...
- 找回被丢弃怎么找都找不回来的git中的commit
崩溃的一天,打算提代码走人,结果切分支之后,commit丢了= =,找了三个多小时 接下来分享下如何找回丢失的commit的 打开项目所在位置,打开git bash,在gitBASH中输入 git f ...