POJ 2676 数独 Dancing-Links(DLX)

题目大意:。。。。数独还用我说么

首先一般的解法都是爆搜,爆搜的话绝对懒得做。。于是我作死去学了Dancing-Links数据结构优化的X算法,简称DLX算法

Dancing-Links虽然名字好听,但是其实实质就是双向十字链表。。但是由于调试的时候各种挂,指针还看着及其闹心(经常调试链式结构的人一定深有同感),所以只能在调试区各种加指针删指针,来回飞舞的指针,即Dancing-Links。。。 

这算法的作者太有才了,不得不说。。。。

DLX算法主要解决的是精确覆盖问题,具体做法见 http://www.cnblogs.com/grenet/p/3145800.html

这里我们要把数独问题转化为精确覆盖问题

首先数独的约束条件是什么?

1.一个格子里只能放一个数

2.每行同一数字只能放一个

3.每列同一数字只能放一个

4.每个九宫格中同一数字只能放一个

于是我们每一行就有四组约束条件:

1.81列,代表这个格子中已经放了数字

2.81列,代表第i行已经放了数字j

3.81列,代表第i列已经放了数字j

4.81列,代表第i个九宫格中已经放了数字j

然后每个格子的每种填放可能作为一行加进去就可以了

记住一定要采用A*算法,不然会死!

每次选择当前拥有1最少的列进行更新,不然必死无疑

最后贴代码 我的head开在了十字链表的最下方 加行比较方便

<pre class="sh_cpp sh_sourceCode" style="background-color: white;font-size:14px; font-family: 'Courier New', Courier, monospace;"><pre name="code" class="html">#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
 
struct abcd *stack[4000];
int top;
 
struct abcd{
	abcd *l,*r,*u,*d;
	int x,y,num;
	abcd *bottom;
	abcd(abcd *L,abcd *R,abcd *U,abcd *D,int X,int Y,int Num)
	{
		l=L;if(L)L->r=this;
		r=R;if(R)R->l=this;
		u=U;if(U)U->d=this;
		d=D;if(D)D->u=this;
		x=X;y=Y;num=Num;
		bottom=d;
		if(bottom)
			bottom->x++;
	}
	void del()
	{
		if(l)l->r=r;
		if(r)r->l=l;
		if(u)u->d=d;
		if(d)d->u=u;
		if(bottom)
			bottom->x--;
		stack[++top]=this;
	}
	void restore()
	{
		if(l)l->r=this;
		if(r)r->l=this;
		if(u)u->d=this;
		if(d)d->u=this;
		if(bottom)
			bottom->x++;
	}
}*head,*heads[400];
int m,n,map[9][9];
bool flag;
void del_column(int pos)
{
	abcd *temp1,*temp2;
	for(temp1=heads[pos]->u;temp1;temp1=temp1->u)
	{
		for(temp2=temp1->l;temp2;temp2=temp2->l)
			temp2->del();
		for(temp2=temp1->r;temp2;temp2=temp2->r)
			temp2->del();
		temp1->del();
	}
	heads[pos]->del();
}
inline void output()
{
	int i,j;
	for(i=0;i<9;i++)
	{
		for(j=0;j<9;j++)
			putchar(map[i][j]+'0');
		putchar('\n');
	}
}
void DLX()
{
	if(!head->r)
	{
		output();
		flag=1;
		return ;
	}
	int bottom=top,minnum=0x7fffffff;
	abcd *temp,*mintemp;
	for(temp=head->r;temp;temp=temp->r)
		if(temp->x<minnum)
			minnum=temp->x,mintemp=temp;
	for(temp=mintemp->u;temp;temp=temp->u)
	{
		int x=temp->x,y=temp->y,num=temp->num;
		map[x][y]=num;

		del_column(x*9+y+1			      );
		del_column(81+x*9+num		      );
		del_column(162+y*9+num	    	  );
		del_column(243+(x/3*3+y/3)*9+num  );
		
		DLX();
		if(flag)
			return ;
		while(top!=bottom)
			stack[top--]->restore();
	}
}
void add(int x,int y,int num)
{
	abcd *last=0x0,*temp;
	temp=heads[x*9+y+1		    	  ],last=new abcd(last,0x0,temp->u,temp,x,y,num);
	temp=heads[81+x*9+num		      ],last=new abcd(last,0x0,temp->u,temp,x,y,num);
	temp=heads[162+y*9+num		      ],last=new abcd(last,0x0,temp->u,temp,x,y,num);
	temp=heads[243+(x/3*3+y/3)*9+num  ],last=new abcd(last,0x0,temp->u,temp,x,y,num);
}
int main()
{
	int T,i,j,k,x;
	abcd *temp,*last;
	 
	//freopen("sudoku.in","r",stdin);
	//freopen("sudoku.out","w",stdout);
	
	for(cin>>T;T;T--)
	{
		head=new abcd(0x0,0x0,0x0,0x0,0,0,0);top=0;flag=0;
		for(i=1,last=head;i<=81*4;i++)
			last=new abcd(last,0x0,0x0,0x0,0,0,i),heads[i]=last;
		for(i=0;i<9;i++)
			for(j=0;j<9;j++)
				scanf("%1d",&map[i][j]);
		for(i=0;i<9;i++)
			for(j=0;j<9;j++)
				if(map[i][j])
					add(i,j,map[i][j]);
				else
					for(k=1;k<=9;k++)
						add(i,j,k);
		DLX();
	}
}


 
 
 
 

你可能感兴趣的:(poj,数独,dlx,poj2676,Dancing-Links)