dancing link 学习资源导航+心得

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代码:

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<cmath>
  6 #include<iomanip> 
  7 using namespace std;
  8 
  9 const int n=729,m=324;
 10 bool mx[2000][2000];
 11 int map[10][10],cnt[2000],head,cur,ans;
 12 int sqr[10][10]={{0,0,0,0,0,0,0,0,0,0},
 13                {0,1,1,1,4,4,4,7,7,7},
 14                {0,1,1,1,4,4,4,7,7,7},
 15                {0,1,1,1,4,4,4,7,7,7},
 16                {0,2,2,2,5,5,5,8,8,8},
 17                {0,2,2,2,5,5,5,8,8,8},
 18                {0,2,2,2,5,5,5,8,8,8},
 19                {0,3,3,3,6,6,6,9,9,9},
 20                {0,3,3,3,6,6,6,9,9,9},
 21                {0,3,3,3,6,6,6,9,9,9}};
 22 
 23 int w[10][10]={{0,0,0,0,0,0,0,0,0,0},
 24                {0,6,6,6,6,6,6,6,6,6},
 25                {0,6,7,7,7,7,7,7,7,6},
 26                {0,6,7,8,8,8,8,8,7,6},
 27                {0,6,7,8,9,9,9,8,7,6},
 28                {0,6,7,8,9,10,9,8,7,6},
 29                {0,6,7,8,9,9,9,8,7,6},
 30                {0,6,7,8,8,8,8,8,7,6},
 31                {0,6,7,7,7,7,7,7,7,6},
 32                {0,6,6,6,6,6,6,6,6,6}};
 33                
 34 struct point
 35 {
 36     int row,lc,rc,up,down,col;
 37 }node[2000*2000];
 38 
 39 inline int id(int x,int y)
 40 {
 41     return (x-1)*9+y;
 42 }
 43 
 44 void init(int c)
 45 {
 46     for (int i=0;i<=c;i++)
 47     {
 48         node[i].lc=i-1;
 49         node[i].rc=i+1;
 50         node[i].up=node[i].down=node[i].col=i;
 51     }
 52     node[0].lc=c;
 53     node[c].rc=0;
 54 }
 55 
 56 void build_link()
 57 {
 58     cur=m;
 59     for (int i=1;i<=n;i++)
 60     {
 61         int start,pre;
 62         start=pre=cur+1;
 63         for (int j=1;j<=m;j++)
 64             if (mx[i][j])
 65             {
 66                 cur++;
 67                 cnt[j]++;
 68                 node[cur].row=i;
 69                 
 70                 node[cur].lc=pre;
 71                 node[cur].rc=start;
 72                 node[pre].rc=cur;
 73                 node[start].lc=cur;
 74                 
 75                 node[cur].col=j;
 76                 node[cur].up=node[j].up;
 77                 node[cur].down=j;
 78                 node[node[j].up].down=cur;
 79                 node[j].up=cur;
 80                 pre=cur;
 81             }
 82     }
 83 }
 84 
 85 inline void cover(int c)
 86 {
 87     for (int i=node[c].up;i!=c;i=node[i].up)
 88         for (int j=node[i].rc;j!=i;j=node[j].rc)
 89         {
 90             node[node[j].up].down=node[j].down;
 91             node[node[j].down].up=node[j].up;
 92             cnt[node[j].col]--;
 93         }
 94     node[node[c].lc].rc=node[c].rc;
 95     node[node[c].rc].lc=node[c].lc;
 96 }
 97 
 98 inline void uncover(int c)
 99 {
100     for (int i=node[c].up;i!=c;i=node[i].up)
101         for (int j=node[i].rc;j!=i;j=node[j].rc)
102         {
103             node[node[j].up].down=j;
104             node[node[j].down].up=j;
105             cnt[node[j].col]++;
106         }
107     node[node[c].lc].rc=c;
108     node[node[c].rc].lc=c;
109 }
110 
111 void read_data()
112 {
113     for (int i=1;i<=9;i++)
114         for (int j=1;j<=9;j++)
115         {
116             scanf("%d",&map[i][j]);
117             int c=id(i,j),t,k;
118             if (map[i][j])
119             {
120                 k=map[i][j];
121                 t=(c-1)*9+k;
122                 mx[t][c]=true;
123                 mx[t][81+9*(i-1)+k]=true;
124                 mx[t][162+9*(j-1)+k]=true;
125                 mx[t][243+(sqr[i][j]-1)*9+k]=true;
126             }
127             else
128             {
129                 for (k=1;k<=9;k++)
130                 {
131                     t=(c-1)*9+k;
132                     mx[t][c]=true;
133                     mx[t][81+9*(i-1)+k]=true;
134                     mx[t][162+9*(j-1)+k]=true;
135                     mx[t][243+(sqr[i][j]-1)*9+k]=true;
136                 }
137             }
138         }
139 }
140 
141 bool dfs(int step,int score)
142 {
143     if (node[head].rc==head)
144     {
145         ans=max(score,ans);
146         return true;
147     }
148     
149     int i,j,c,t=210000,x,y,num,flag=0;
150     for (i=node[head].rc;i!=head;i=node[i].rc)
151         if (cnt[i]<t)
152         {
153             t=cnt[i];
154             c=i;
155         }
156     if (t==0)
157         return false;
158     cover(c);
159     
160     for (i=node[c].down;i!=c;i=node[i].down)
161     {
162         for (j=node[i].lc;j!=i;j=node[j].lc)
163             cover(node[j].col);
164         num=(node[i].row-1)/9+1;
165         x=(num-1)/9+1;
166         y=num-9*(x-1);
167         flag|=dfs(step+1,score+w[x][y]*(node[i].row-(num-1)*9));
168         for (j=node[i].rc;j!=i;j=node[j].rc)
169             uncover(node[j].col);
170     }
171     
172     uncover(c);
173     return flag;
174 }
175 
176 void solve()
177 {
178     init(m);
179     build_link();
180     int flag=1;
181     if (!dfs(1,0))
182         printf("-1\n");
183     else printf("%d\n",ans);
184 }
185 
186 int main()
187 {
188     //freopen("in.in","r",stdin);
189     //freopen("out.out","w",stdout);
190     read_data();
191     solve();
192     return 0;
193 } 
View Code


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

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<cmath>
  6 #include<iomanip> 
  7 using namespace std;
  8 
  9 const int n=729,m=324;
 10 bool mx[2000][2000];
 11 int map[10][10],cnt[2000],head,cur,ans[10][10];
 12 int sqr[10][10]={{0,0,0,0,0,0,0,0,0,0},
 13                {0,1,1,1,4,4,4,7,7,7},
 14                {0,1,1,1,4,4,4,7,7,7},
 15                {0,1,1,1,4,4,4,7,7,7},
 16                {0,2,2,2,5,5,5,8,8,8},
 17                {0,2,2,2,5,5,5,8,8,8},
 18                {0,2,2,2,5,5,5,8,8,8},
 19                {0,3,3,3,6,6,6,9,9,9},
 20                {0,3,3,3,6,6,6,9,9,9},
 21                {0,3,3,3,6,6,6,9,9,9}};
 22                
 23 struct point
 24 {
 25     int row,lc,rc,up,down,col;
 26 }node[2000*2000];
 27 
 28 inline int id(int x,int y)
 29 {
 30     return (x-1)*9+y;
 31 }
 32 
 33 void init(int c)
 34 {
 35     for (int i=0;i<=c;i++)
 36     {
 37         node[i].lc=i-1;
 38         node[i].rc=i+1;
 39         node[i].up=node[i].down=node[i].col=i;
 40     }
 41     node[0].lc=c;
 42     node[c].rc=0;
 43 }
 44 
 45 void build_link()
 46 {
 47     cur=m;
 48     for (int i=1;i<=n;i++)
 49     {
 50         int start,pre;
 51         start=pre=cur+1;
 52         for (int j=1;j<=m;j++)
 53             if (mx[i][j])
 54             {
 55                 cur++;
 56                 cnt[j]++;
 57                 node[cur].row=i;
 58                 
 59                 node[cur].lc=pre;
 60                 node[cur].rc=start;
 61                 node[pre].rc=cur;
 62                 node[start].lc=cur;
 63                 
 64                 node[cur].col=j;
 65                 node[cur].up=node[j].up;
 66                 node[cur].down=j;
 67                 node[node[j].up].down=cur;
 68                 node[j].up=cur;
 69                 pre=cur;
 70             }
 71     }
 72 }
 73 
 74 inline void cover(int c)
 75 {
 76     for (int i=node[c].up;i!=c;i=node[i].up)
 77         for (int j=node[i].rc;j!=i;j=node[j].rc)
 78         {
 79             node[node[j].up].down=node[j].down;
 80             node[node[j].down].up=node[j].up;
 81             cnt[node[j].col]--;
 82         }
 83     node[node[c].lc].rc=node[c].rc;
 84     node[node[c].rc].lc=node[c].lc;
 85 }
 86 
 87 inline void uncover(int c)
 88 {
 89     for (int i=node[c].up;i!=c;i=node[i].up)
 90         for (int j=node[i].rc;j!=i;j=node[j].rc)
 91         {
 92             node[node[j].up].down=j;
 93             node[node[j].down].up=j;
 94             cnt[node[j].col]++;
 95         }
 96     node[node[c].lc].rc=c;
 97     node[node[c].rc].lc=c;
 98 }
 99 
100 void read_data()
101 {
102     for (int i=1;i<=9;i++)
103         for (int j=1;j<=9;j++)
104         {
105             char g;
106             scanf(" %c",&g);
107             map[i][j]=(int)g-'0';
108             int c=id(i,j),t,k;
109             if (map[i][j])
110             {
111                 k=map[i][j];
112                 t=(c-1)*9+k;
113                 mx[t][c]=true;
114                 mx[t][81+9*(i-1)+k]=true;
115                 mx[t][162+9*(j-1)+k]=true;
116                 mx[t][243+(sqr[i][j]-1)*9+k]=true;
117             }
118             else
119             {
120                 for (k=1;k<=9;k++)
121                 {
122                     t=(c-1)*9+k;
123                     mx[t][c]=true;
124                     mx[t][81+9*(i-1)+k]=true;
125                     mx[t][162+9*(j-1)+k]=true;
126                     mx[t][243+(sqr[i][j]-1)*9+k]=true;
127                 }
128             }
129         }
130 }
131 
132 void print()
133 {
134     for (int i=1;i<=9;i++)
135     {
136         for (int j=1;j<=9;j++)
137             printf("%d",ans[i][j]);
138         printf("\n");
139     }
140 }
141 
142 bool dfs(int step)
143 {
144     if (node[head].rc==head)
145     {
146         print();
147         return true;
148     }
149     
150     int i,j,c,t=210000,x,y,num,flag=0;
151     for (i=node[head].rc;i!=head;i=node[i].rc)
152         if (cnt[i]<t)
153         {
154             t=cnt[i];
155             c=i;
156         }
157     if (t==0)
158         return false;
159     cover(c);
160     
161     for (i=node[c].down;i!=c;i=node[i].down)
162     {
163         for (j=node[i].lc;j!=i;j=node[j].lc)
164             cover(node[j].col);
165         num=(node[i].row-1)/9+1;
166         x=(num-1)/9+1;
167         y=num-9*(x-1);
168         ans[x][y]=node[i].row-(num-1)*9;
169         if (dfs(step+1))
170             return true;
171         for (j=node[i].rc;j!=i;j=node[j].rc)
172             uncover(node[j].col);
173     }
174     
175     uncover(c);
176     return false;
177 }
178 
179 void solve()
180 {
181     init(m);
182     build_link();
183     if (!dfs(1))
184         printf("-1\n");
185 }
186 
187 int main()
188 {
189     freopen("alone.in","r",stdin);
190     freopen("alone.out","w",stdout);
191     read_data();
192     solve();
193     return 0;
194 } 
View Code

 

转载于:https://www.cnblogs.com/vb4896/p/3933685.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值