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. PyQt 学习笔记1——自定义窗口框架

    自定义一个属于自己的窗口,初始化时自动设置好在屏幕中央显示,重写退出事件的触发器 closeEvent(),并增加了设置图标,简化设置标题的函数名,其它类可以继承它: # -*- coding: ut ...

  2. Android 异步加载图片,使用LruCache和SD卡或手机缓存,效果非常的流畅

      Android 高手进阶(21)  版权声明:本文为博主原创文章,未经博主允许不得转载. 转载请注明出处http://blog.csdn.net/xiaanming/article/details ...

  3. Maven——聚合与继承

    原文:http://www.cnblogs.com/xdp-gacl/p/4058008.html 一.聚合 如果我们想一次构建多个项目模块,那我们就需要对多个项目模块进行聚合 1.1.聚合配置代码 ...

  4. 【ufldl tutorial】Softmax Regression

    今天太长姿势了,什么叫懂了也写不出代码说的不就是我吗,就那么几行代码居然叽叽歪歪写了一个小时. 首先exercise要实现的是softmax的cost function和gradient,如下图: ( ...

  5. Hbase之更新单条数据

    import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.HBaseConfiguration; impo ...

  6. 提高php开发效率的9大代码片段

    在网站开发中,我们都期望能高效快速的进行程序开发,如果有能直接使用的代码片段,提高开发效率,那将是极好的.php开发福利来了,今天小编就将为大家分享9大超实用的.可节省大量开发时间的php代码片段. ...

  7. 栈 - 从零开始实现by C++

    参考链接:数据结构探险-栈篇 学了队列之后,栈就很简单了,换汤不换药.   栈 栈的模型 后进先出(电梯,进制转换,括号的匹配检测)   栈的基本元素 栈顶,栈底(一般很少用到),栈容量,栈长度 注意 ...

  8. Linux安装多个Python版本

    服务器上的Python版本太老了,需要安装一个新的Python版本,才能跑我的代码.因为环境的需要,但是又不能卸载老的版本,所以安装一个新的,使用软链来进行升级. 使用系统自带的yum,apt-get ...

  9. 解决点击a标签返回页面顶部的问题

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. Completely disable mousewheel on a WinForm

    this.MouseWheel += new MouseEventHandler(Form_MouseWheel); private void Form_MouseWheel(object sende ...