dancing link简直是求解数独的神器,NOIP2009最后一题靶形数独,DFS 各种改变搜索顺序 都没法过,最后还是用了卡时过得。用dancing link写,秒杀所有数据,总时间才400ms不到。。(虽然还不是很清楚为什么会快)。

一开始还是先看这个blog,图文都非常清晰

http://www.cnblogs.com/grenet/p/3145800.html

上文解释了dancing link的原理,可以用来解决精度覆盖问题,但是求解数独问题还需要一步转化。

见博文:

http://www.cnblogs.com/grenet/p/3163550.html

大致思想是:

1、先遍历数独的格子,把那些有数字的格子转换为行,插入到矩阵中。在插入的同时,把包含1的列的列首元素的Count分量设置为-1(起到后面判别的作用)。

由于这些行一定能被选中,是答案的一部分,那么把这些行的行号置入到答案列表中,并把这些列的列首元素从水平双向链中移除(手动移除比调用RemoveCol方法快)

2、在遍历没有数字的格子,转换为若干行(1个格子9行)插入到矩阵中。在插入到矩阵的时候,判断包含1的列的列首元素的Count分量。如果是-1,说明新插入的行和第1步中的某些行相冲,是个无效行,没有必要插入到矩阵中;如果不是-1,说明是个有效行,插入到矩阵中。

这样把就数独转化成一个729*324的精度覆盖问题;

看了这个大致有些明白,但要是自己写还是无从下手,先看一个模板(注释比较清晰易懂):

http://blog.csdn.net/weiguang_123/article/details/7935003

看完后可以尝试着做一做裸的精度覆盖问题poj3740,然后再去做靶形数独。

另外第一篇文章中有个地方:

在函数中有个很聪明的设计,在标示列首元素时,顺序是从I元素的右侧元素开始;而在回标列首元素时,顺序是从I元素的左侧元素开始,正好顺序和标示列首元素的顺序相反。

这里非常关键,本来以为无关紧要,把poj3740的代码 顺序改成一样,还是能AC,不过时间慢了一半, 还以为这是个优化时间的地方。但是把靶形数独的代码改成这样,就WA了一半的点,手工模拟下可以发现这个顺序问题不是可有可无的,而是必须的。

贴上我靶形数独的AC代码:

 #include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iomanip>
using namespace std; const int n=,m=;
bool mx[][];
int map[][],cnt[],head,cur,ans;
int sqr[][]={{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,}}; int w[][]={{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,}}; struct point
{
int row,lc,rc,up,down,col;
}node[*]; inline int id(int x,int y)
{
return (x-)*+y;
} void init(int c)
{
for (int i=;i<=c;i++)
{
node[i].lc=i-;
node[i].rc=i+;
node[i].up=node[i].down=node[i].col=i;
}
node[].lc=c;
node[c].rc=;
} void build_link()
{
cur=m;
for (int i=;i<=n;i++)
{
int start,pre;
start=pre=cur+;
for (int j=;j<=m;j++)
if (mx[i][j])
{
cur++;
cnt[j]++;
node[cur].row=i; node[cur].lc=pre;
node[cur].rc=start;
node[pre].rc=cur;
node[start].lc=cur; node[cur].col=j;
node[cur].up=node[j].up;
node[cur].down=j;
node[node[j].up].down=cur;
node[j].up=cur;
pre=cur;
}
}
} inline void cover(int c)
{
for (int i=node[c].up;i!=c;i=node[i].up)
for (int j=node[i].rc;j!=i;j=node[j].rc)
{
node[node[j].up].down=node[j].down;
node[node[j].down].up=node[j].up;
cnt[node[j].col]--;
}
node[node[c].lc].rc=node[c].rc;
node[node[c].rc].lc=node[c].lc;
} inline void uncover(int c)
{
for (int i=node[c].up;i!=c;i=node[i].up)
for (int j=node[i].rc;j!=i;j=node[j].rc)
{
node[node[j].up].down=j;
node[node[j].down].up=j;
cnt[node[j].col]++;
}
node[node[c].lc].rc=c;
node[node[c].rc].lc=c;
} void read_data()
{
for (int i=;i<=;i++)
for (int j=;j<=;j++)
{
scanf("%d",&map[i][j]);
int c=id(i,j),t,k;
if (map[i][j])
{
k=map[i][j];
t=(c-)*+k;
mx[t][c]=true;
mx[t][+*(i-)+k]=true;
mx[t][+*(j-)+k]=true;
mx[t][+(sqr[i][j]-)*+k]=true;
}
else
{
for (k=;k<=;k++)
{
t=(c-)*+k;
mx[t][c]=true;
mx[t][+*(i-)+k]=true;
mx[t][+*(j-)+k]=true;
mx[t][+(sqr[i][j]-)*+k]=true;
}
}
}
} bool dfs(int step,int score)
{
if (node[head].rc==head)
{
ans=max(score,ans);
return true;
} int i,j,c,t=,x,y,num,flag=;
for (i=node[head].rc;i!=head;i=node[i].rc)
if (cnt[i]<t)
{
t=cnt[i];
c=i;
}
if (t==)
return false;
cover(c); for (i=node[c].down;i!=c;i=node[i].down)
{
for (j=node[i].lc;j!=i;j=node[j].lc)
cover(node[j].col);
num=(node[i].row-)/+;
x=(num-)/+;
y=num-*(x-);
flag|=dfs(step+,score+w[x][y]*(node[i].row-(num-)*));
for (j=node[i].rc;j!=i;j=node[j].rc)
uncover(node[j].col);
} uncover(c);
return flag;
} void solve()
{
init(m);
build_link();
int flag=;
if (!dfs(,))
printf("-1\n");
else printf("%d\n",ans);
} int main()
{
//freopen("in.in","r",stdin);
//freopen("out.out","w",stdout);
read_data();
solve();
return ;
}

如果要输出数独填好之后的结果,且数独的解唯一,代码如下:

 #include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iomanip>
using namespace std; const int n=,m=;
bool mx[][];
int map[][],cnt[],head,cur,ans[][];
int sqr[][]={{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,}}; struct point
{
int row,lc,rc,up,down,col;
}node[*]; inline int id(int x,int y)
{
return (x-)*+y;
} void init(int c)
{
for (int i=;i<=c;i++)
{
node[i].lc=i-;
node[i].rc=i+;
node[i].up=node[i].down=node[i].col=i;
}
node[].lc=c;
node[c].rc=;
} void build_link()
{
cur=m;
for (int i=;i<=n;i++)
{
int start,pre;
start=pre=cur+;
for (int j=;j<=m;j++)
if (mx[i][j])
{
cur++;
cnt[j]++;
node[cur].row=i; node[cur].lc=pre;
node[cur].rc=start;
node[pre].rc=cur;
node[start].lc=cur; node[cur].col=j;
node[cur].up=node[j].up;
node[cur].down=j;
node[node[j].up].down=cur;
node[j].up=cur;
pre=cur;
}
}
} inline void cover(int c)
{
for (int i=node[c].up;i!=c;i=node[i].up)
for (int j=node[i].rc;j!=i;j=node[j].rc)
{
node[node[j].up].down=node[j].down;
node[node[j].down].up=node[j].up;
cnt[node[j].col]--;
}
node[node[c].lc].rc=node[c].rc;
node[node[c].rc].lc=node[c].lc;
} inline void uncover(int c)
{
for (int i=node[c].up;i!=c;i=node[i].up)
for (int j=node[i].rc;j!=i;j=node[j].rc)
{
node[node[j].up].down=j;
node[node[j].down].up=j;
cnt[node[j].col]++;
}
node[node[c].lc].rc=c;
node[node[c].rc].lc=c;
} void read_data()
{
for (int i=;i<=;i++)
for (int j=;j<=;j++)
{
char g;
scanf(" %c",&g);
map[i][j]=(int)g-'';
int c=id(i,j),t,k;
if (map[i][j])
{
k=map[i][j];
t=(c-)*+k;
mx[t][c]=true;
mx[t][+*(i-)+k]=true;
mx[t][+*(j-)+k]=true;
mx[t][+(sqr[i][j]-)*+k]=true;
}
else
{
for (k=;k<=;k++)
{
t=(c-)*+k;
mx[t][c]=true;
mx[t][+*(i-)+k]=true;
mx[t][+*(j-)+k]=true;
mx[t][+(sqr[i][j]-)*+k]=true;
}
}
}
} void print()
{
for (int i=;i<=;i++)
{
for (int j=;j<=;j++)
printf("%d",ans[i][j]);
printf("\n");
}
} bool dfs(int step)
{
if (node[head].rc==head)
{
print();
return true;
} int i,j,c,t=,x,y,num,flag=;
for (i=node[head].rc;i!=head;i=node[i].rc)
if (cnt[i]<t)
{
t=cnt[i];
c=i;
}
if (t==)
return false;
cover(c); for (i=node[c].down;i!=c;i=node[i].down)
{
for (j=node[i].lc;j!=i;j=node[j].lc)
cover(node[j].col);
num=(node[i].row-)/+;
x=(num-)/+;
y=num-*(x-);
ans[x][y]=node[i].row-(num-)*;
if (dfs(step+))
return true;
for (j=node[i].rc;j!=i;j=node[j].rc)
uncover(node[j].col);
} uncover(c);
return false;
} void solve()
{
init(m);
build_link();
if (!dfs())
printf("-1\n");
} int main()
{
freopen("alone.in","r",stdin);
freopen("alone.out","w",stdout);
read_data();
solve();
return ;
}

dancing link 学习资源导航+心得的更多相关文章

  1. 从入门到精通,Java学习路线导航(附学习资源)

    原文链接:https://blog.csdn.net/qq_42453117/article/details/100655512 引言 最近也有很多人来向我"请教",他们大都是一些 ...

  2. angularJS学习资源最全汇总

    基础 官方: http://docs.angularjs.org angularjs官方网站已被墙,可看 http://www.ngnice.com/: 官方zip下载包 https://github ...

  3. iOS 学习资源

    这份学习资料是为 iOS 初学者所准备的, 旨在帮助 iOS 初学者们快速找到适合自己的学习资料, 节省他们搜索资料的时间, 使他们更好的规划好自己的 iOS 学习路线, 更快的入门, 更准确的定位的 ...

  4. 【转载】分享一些Qt学习资源,欢迎下载

    资源来源:http://bbs.csdn.net/topics/390358737 经过我一翻整理,把一些我收集到的Qt学习资源分享给大家,主要适合新手,老鸟可以直接忽略我.要说明一下,很多资源都是在 ...

  5. Git 操作 学习资源 网址

    用git 有一段时间了,有点自己的小心得.个人觉得相对SVN来讲他更灵活,更合理. 陆陆续续的收集了一些学习资源: 1.理解Xcode 中的Git 版本控制 http://www.open-open. ...

  6. 12套swift学习资源分享

    虽然objective-c编程语言在过去很长一段时间都是iOS应用开发的基础语言,且很多iOS开发者对其也深爱有佳,但是随着swift编程语言的问世,迅速发展为开发者追捧的语言.且今年伴随着swift ...

  7. WEB前端学习资源清单

    常用学习资源 JS参考与基础学习系列 [MDN]JS标准参考 es6教程 JS标准参考教程 编程类中文书籍索引 深入理解JS系列 前端开发仓库 <JavaScript 闯关记> JavaS ...

  8. Sublime text 入门学习资源篇及其基本使用方法

    Sublime text 学习资源篇 史上最性感的编辑器-sublimetext,插件, 学习资源 官网 http://www.sublimetext.com/ 插件 https://packagec ...

  9. (转) 深度强化学习综述:从AlphaGo背后的力量到学习资源分享(附论文)

    本文转自:http://mp.weixin.qq.com/s/aAHbybdbs_GtY8OyU6h5WA 专题 | 深度强化学习综述:从AlphaGo背后的力量到学习资源分享(附论文) 原创 201 ...

随机推荐

  1. [LED]如何配置LCD背光和LED,调试方法

    [DESCRIPTION] 如何配置LCD背光和LED,调试方法 [SOLUTION]LCD背光和LED配置文件alps/custom/<proj name>lk/cust_leds.ca ...

  2. thinkphp3.2+PHPExcel导出查询数据到excel表格的实例

    首先下载PHPExcel插件,我们需要把PHPExcel.php和PHPExcel文件夹放到D:\XAMPP\htdocs\fsxb\ThinkPHP\Library\Vendor\PHPExcel目 ...

  3. Oracle分析函数的项目实践实例

    SELECT * FROM SSE2_FLOW_EXPENSE T1 JOIN (SELECT SFEL.*, ROW_NUMBER() OVER(PARATITION BY SFEL.FE_EXPE ...

  4. JavaWeb学习总结(一)—JavaWeb开发入门及环境搭建

    一.基本概念 1.1.软件体系结构 1.C/S:Client/Servlet,例如QQ就是CS结构需要编写服务器端程序和客户端程序.缺点:更新需要两端,总要求客户下载新的客户端程序优点:安全性比较好2 ...

  5. Linux之free命令

    from http://www.cnblogs.com/peida/archive/2012/12/25/2831814.html free命令可以显示Linux系统中空闲的.已用的物理内存及swap ...

  6. 【Todo】LR-逻辑回归

    因为逻辑回归对于计算广告学非常重要.也是我们平时广告推荐.CTR预估最常用到的算法.所以单独开一篇文章讨论. 参考这篇文章:http://www.cnblogs.com/sparkwen/p/3441 ...

  7. SonarLint插件的安装与使用

    注意:版本要求Eclipse(4.2,3.8)以上,Java3.1.2,JavaScript 2. 一.SonarLint插件的安装方式 1.安装方式一:在线安装 1)Eclipse工具栏选择Help ...

  8. RecyleView

    RecyclerView是经典的ListView的进化与升华,它比ListView更加灵活,但也因此引入了一定的复杂性. 我们知道,ListView通过使用ViewHolder来提升性能.ViewHo ...

  9. commonJS — 数字操作(for Number)

    for Number github: https://github.com/laixiangran/commonJS/blob/master/src/forNumber.js 代码 /** * Cre ...

  10. 任务栏右键工具栏里的语言栏没有的修复.reg

    任务栏右键工具栏里的语言栏没有的修复.reg Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\CLSID\{540D8A8B-1C3F- ...