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. Python学习笔记16—电子表格

    openpyl 模块是解决 Microsoft Excel 2007/2010 之类版本中扩展名是 Excel 2010 xlsx/xlsm/xltx/xltm 的文件的读写的第三方库. 安装 pip ...

  2. Python学习笔记8—语句

    条件语句 有的程序里写的是 /usr/bin Python,表示 Python 解释器在/usr/bin 里面.但是,如果写成 /usr/bin/env,则表示要通过系统搜索路径寻找 Python 解 ...

  3. 【Todo】Nginx架构学习

    要进行Web服务,绕不开的就是Nginx.这已经是大型网站的标配.对Nginx进行一定程度的深入学习. http://www.ituring.com.cn/article/4436 http://bl ...

  4. Eclipse用Tomcat插件部署Java Web项目

    Eclipse版本3.7.2,Tomcat插件是3.3 详细步骤如下: 1.下载tomcatPlugin插件 tomcatPlugin下载地址http://download.csdn.net/deta ...

  5. Freemarker 入门示例(zhuan)

    http://cuisuqiang.iteye.com/blog/2031768 ************************************ 初步学习freemarker ,先做一个简单 ...

  6. C#_抓包HttpWebRequest跟HttpWebResponse

    1.第一招,根据URL地址获取网页信息  这招是入门第一式, 特点: 1.最简单最直观的一种,入门课程. 2.适应于明文,无需登录,无需任何验证就可以进入的页面. 3.获取的数据类型为HTML文档. ...

  7. Appium 切换上下文环境

    Appium 切换上下文环境,代码如下: private void switchToContext(String sContext) { LogManager.getLogger(this.getCl ...

  8. jquery 全选功能

    1.直接全选(复选框名字要统一) <input type="CHECKBOX" id="cbSelectAll" onclick="$('inp ...

  9. 基于SourceTree 下的 Git Flow 模型

    基于SourceTree 下的 Git Flow 模型 1. sourceTree  是一个开源的git 图形管理工具,可下载mac版本,windows版本 2. Git Flow 是一套使用Git进 ...

  10. VC++源文件编码

    目录 第1章源代码文件    1 1.1 研究思路    1 1.2 实验结果    3 1.3 #pragma setlocale    4 1.4 /source-charset    5 1.5 ...