【POJ3074】Sudoku DLX(Dancing Links)

数独就要DLX,不然不乐意。

数独的DLX构造:9*9个点每一个点有9种选择,这构成了DLX的729行,每行、列、阵有限制,均为9行(/列/阵),然后每行(/列/阵)都有九种数的情况。于是就有了3*9*9列。可是由于一个位置仅仅能选一个,所以又有9*9列,每列连接一个点的九种选数情况。

终于有4*9*9=324列,9*9*9=729行。

处理:

有些点已经有数了,可是这并不重要,我们仅仅须要给这个点加上一个行,为它已经选的数。而不要把9种情况都加上,这样在有精确覆盖的情况下(即有解),第四部分的某列在纵向就仅仅连接一个节点,显然这个节点是必选的,所以不会出错(当然你要是依旧给这个有值节点在DLX中加9行的话。那我也没招,不要问我为什么错,好吧你不会这么傻吧?)。

而其他没有初始值的数独点,自然就加旧行了没疑问吧?

说一个跟空间复杂度相关的事。就是一行有且仅有4个节点。分别在行、列、阵、位置这四部分的列中,那么总节点数(不算辅助节点)就应该最多是729*4。而实际上标准数独都是有唯一解的,所以须要的节点将远远小于这个数。

再说说时间复杂度:由于我们能够为DLX加一个优化。就是每次选一个列中节点最少的列继续DLX的过程,所以我们尽管保留了已经有值的节点,可是实际上最開始就选择了它们,而若数独有解。这也是必然选择的。所以并不会出现由于层数过多而导致回溯过度而TLE的情况,也就是说它还是非常快的。当然。强迫症神马的我也管不了。你要是乐意把已赋值点删掉我也不拦着,但不像上一篇代码了。你要这么写的话,我并不会给你提供代码支持。

事实上这么写最重要的原因就是:代。码!好!

写!

好吧,我把我好写好读的代码贴上来吧!提示:要读代码先看define!事实上这道题的define非常easy。并没有一些恶心人的for循环define,你要是认为读着恶心一定是你的问题了。

贴代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 800
#define M 400
#define NN 5000
#define inf 0x3f3f3f3f

#define Li_Sdk 3
#define Gi_Sdk 9
#define Su_Sdk 81
using namespace std;
char TS[N];
struct DLX
{
	int elist,eline;
	int id[Gi_Sdk+1][Gi_Sdk+1][Gi_Sdk+1];
	int eid[4][Gi_Sdk][Gi_Sdk];
	bool map[M][N];

	int U[NN],D[NN],L[NN],R[NN],C[NN],V[NN];
	int H[N],T[M],cnt;
	int ans[NN];
	bool visit[M],vist[M];

	inline void init()
	{
		int i,j,k,_i,_j;
		for(i=1;i<=Gi_Sdk;i++)
			for(j=1;j<=Gi_Sdk;j++)
				for(k=1;k<=Gi_Sdk;k++)
					id[i][j][k]=++eline;
		for(i=1;i<=Gi_Sdk;i++)/*行*/
		{
			for(j=1;j<=Gi_Sdk;j++)/*数*/
			{
				int A=eid[0][i][j]=++elist;
				for(k=1;k<=Gi_Sdk;k++)/*列*/
				{
					int B=id[i][k][j];
					map[A][B]=1;
				}
			}
		}
		for(i=1;i<=Gi_Sdk;i++)/*列*/
		{
			for(j=1;j<=Gi_Sdk;j++)/*数*/
			{
				int A=eid[1][i][j]=++elist;
				for(k=1;k<=Gi_Sdk;k++)/*行*/
				{
					int B=id[k][i][j];
					map[A][B]=1;
				}
			}
		}
		for(i=0;i<Li_Sdk;i++)for(j=0;j<Li_Sdk;j++)/*九宫格*/
		{
			for(k=1;k<=Gi_Sdk;k++)/*数*/
			{
				int A=eid[2][i*Li_Sdk+j+1][k]=++elist;
				for(_i=1;_i<=Li_Sdk;_i++)for(_j=1;_j<=Li_Sdk;_j++)/*格内点*/
				{
					int B=id[i*Li_Sdk+_i][j*Li_Sdk+_j][k];
					map[A][B]=1;
				}
			}
		}
		for(i=1;i<=Gi_Sdk;i++)for(j=1;j<=Gi_Sdk;j++)/*点的位置*/
		{
			int A=eid[3][i][j]=++elist;
			for(k=1;k<=Gi_Sdk;k++)/*点的9个数*/
			{
				int B=id[i][j][k];
				map[A][B]=1;
			}
		}
/*		for(j=1;j<=eline;j++)
		{
			for(i=1;i<=elist;i++)
			{
				printf("%d",map[i][j]);
			}
			puts("");
		}
*/		/*本题的数独是正常数独,所以有下面固定信息。*/
		/*合计eline即DLX的行有9*9*9=729行,即每一个位置的九种数字选择。*/
		/*合计elist即DLX的列有4*9*9=324列。即行、列、九宫格、位置的4种精确覆盖*/
	}
	inline void clear()
	{
		cnt=0;
		memset(U,0,sizeof(U));
		memset(D,0,sizeof(D));
		memset(L,0,sizeof(L));
		memset(R,0,sizeof(R));
		memset(C,0,sizeof(C));
		memset(H,0,sizeof(H));
		memset(T,0,sizeof(T));
		memset(ans,0,sizeof(ans));
		memset(vist,0,sizeof(vist));
		memset(visit,0,sizeof(visit));
	}
	inline void newnode(int x,int y)
	{
		C[++cnt]=y;V[cnt]=x;T[y]++;

		if(!H[x])H[x]=L[cnt]=R[cnt]=cnt;
		else L[cnt]=H[x],R[cnt]=R[H[x]];
		R[H[x]]=L[R[H[x]]]=cnt,H[x]=cnt;

		U[cnt]=U[y],D[cnt]=y;
		U[y]=D[U[y]]=cnt;
	}
	inline void remove(int x)
	{
		for(int i=D[x];i!=x;i=D[i])
		{
			for(int j=R[i];j!=i;j=R[j])
			{
				U[D[j]]=U[j];
				D[U[j]]=D[j];
				T[C[j]]--;
			}
		}
		L[R[x]]=L[x];
		R[L[x]]=R[x];
	}
	inline void resume(int x)
	{
		for(int i=U[x];i!=x;i=U[i])
		{
			for(int j=L[i];j!=i;j=L[j])
			{
				U[D[j]]=j;
				D[U[j]]=j;
				T[C[j]]++;
			}
		}
		L[R[x]]=x;
		R[L[x]]=x;
	}
	inline void build()
	{
		clear();
		int i,j,k;
		cnt=4*Su_Sdk;
		for(i=1;i<=cnt;i++)
		{
			U[i]=D[i]=i;
			L[i]=L[0],R[i]=0;
			L[0]=R[L[0]]=i;
		}
		for(i=0;i<Gi_Sdk;i++)for(j=0;j<Gi_Sdk;j++)
		{
			int get=i*Gi_Sdk+j;
			int alp=TS[get]-‘.‘;
			if(!alp)
			{
				for(k=get*Gi_Sdk+1;k<=get*Gi_Sdk+Gi_Sdk;k++)
					for(int temp=1;temp<=elist;temp++)
						if(map[temp][k])newnode(k,temp);
			}
			else
			{
				k=get*Gi_Sdk+TS[get]-‘0‘;
				for(int temp=1;temp<=elist;temp++)
					if(map[temp][k])newnode(k,temp);
			}
		}
	}
	inline bool dfs()
	{
		if(!R[0])return true;
		int S=R[0],W=T[S],i,j;
		for(i=R[S];i;i=R[i])if(T[i]<W)
		{
			W=T[i];
			S=i;
		}
		remove(S);
		for(i=D[S];i!=S;i=D[i])
		{
			ans[(V[i]-1)/9]=(V[i]-1)%9+1;
			for(j=R[i];j!=i;j=R[j])remove(C[j]);
			if(dfs())return true;
			for(j=L[i];j!=i;j=L[j])resume(C[j]);
		}
		resume(S);
		return false;
	}
	inline void ret(){for(int i=0;i<Su_Sdk;i++)printf("%d",ans[i]);}
}dlx;
int main()
{
//	freopen("test.in","r",stdin);
//	freopen("my.out","w",stdout);
	int n,m;
	dlx.init();
	while(scanf("%s",TS),TS[0]!=‘e‘)
	{
		dlx.build();
		dlx.dfs();
		dlx.ret();
		puts("");
	}
//	fclose(stdin);
//	fclose(stdout);
	return 0;
}
时间: 2024-10-16 13:27:00

【POJ3074】Sudoku DLX(Dancing Links)的相关文章

【POJ3740】Easy Finding DLX(Dancing Links)精确覆盖问题

题意:多组数据.每组数据给你几行数,要求选出当中几行,使得每一列都有且仅有一个1,询问是可不可行,或者说能不能找出来. 题解:1.暴搜.2.DLX(Dancing links). 本文写的是DLX. 算法參考白书P406或者http://www.cnblogs.com/grenet/p/3145800.html 我说一些仔细的东西,就是删除操作的形状是 | --|---- --|---- --|---- 被删除的点们之间的联系不用删,能够保留.准确地说它并非删去了这些点,而是删去这个形. 并且恢

【NOIP2009】靶形数独 DLX(Dancing Links)

[NOIP2009]靶形数独 T4 Time Limit: 2 Sec  Memory Limit: 128 MB Description 小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他们想用数独来一比高低.但普通的数独对他们来说都过于简单了,于是他们向Z 博士请教,Z 博士拿出了他最近发明的"靶形数独",作为这两个孩子比试的题目. 靶形数独的方格同普通数独一样,在 9 格宽×9 格高的大九宫格中有9 个3 格宽×3 格高的小九宫格(用粗黑色线隔开的).在

ZOJ 3209 Treasure Map (Dancing Links)

Treasure Map Time Limit: 2 Seconds      Memory Limit: 32768 KB Your boss once had got many copies of a treasure map. Unfortunately, all the copies are now broken to many rectangular pieces, and what make it worse, he has lost some of the pieces. Luck

跳跃的舞者,舞蹈链(Dancing Links)算法——求解精确覆盖问题(转)

跳跃的舞者,舞蹈链(Dancing Links)算法——求解精确覆盖问题 转:http://www.cnblogs.com/grenet/p/3145800.html 精确覆盖问题的定义:给定一个由0-1组成的矩阵,是否能找到一个行的集合,使得集合中每一列都恰好包含一个1 例如:如下的矩阵 就包含了这样一个集合(第1.4.5行) 如何利用给定的矩阵求出相应的行的集合呢?我们采用回溯法 矩阵1: 先假定选择第1行,如下所示: 如上图中所示,红色的那行是选中的一行,这一行中有3个1,分别是第3.5.

数组splay ------ luogu P3369 【模板】普通平衡树(Treap/SBT)

二次联通门 : luogu P3369 [模板]普通平衡树(Treap/SBT) #include <cstdio> #define Max 100005 #define Inline __attri\ bute__( ( optimize( "-O2" ) ) ) Inline void read (int &now) { now = 0; register char word = getchar (); bool temp = false; while (wor

luogu P3808 【模板】AC自动机(简单版)

二次联通门 : luogu P3808 [模板]AC自动机(简单版) /* luogu P3808 [模板]AC自动机(简单版) 手速越来越快了 10分钟一个AC自动机 一遍过编译 + 一边AC 感觉不错 我也就做做板子题了.. */ #include <iostream> #include <cstring> #include <cstdio> #include <queue> #define Max 1000009 void read (int &

替罪羊树 ------ luogu P3369 【模板】普通平衡树(Treap/SBT)

二次联通门 : luogu P3369 [模板]普通平衡树(Treap/SBT) 闲的没事,把各种平衡树都写写 比较比较... 下面是替罪羊树 #include <cstdio> #include <vector> #define Max_ 100010 #define Inline __attri\ bute__( ( optimize( "-O2" ) ) ) Inline void read (int &now) { register char w

【转载】视频编码(H264概述)

一视频编码介绍 1.1 视频压缩编码的目标 1)保证压缩比例 2)保证恢复的质量 3)易实现,低成本,可靠性 1.2 压缩的出发点(可行性) 1)时间相关性 在一组视频序列中,相邻相邻两帧只有极少的不同之处,这便是时间相关性. 2)空间相关性 在同一帧中,相邻象素之间有很大的相关性,两象素越近,侧相关性越强. 根据采用的信源的模型分类: 1)基于波形的编码 如果采用“一幅图像由许多象素构成”的信源模型,这种信源模型的参数就是象素的亮度和色度的幅度值,对这些参数进行编码的技术即为基于波形编码. 2

【转】Logistic regression (逻辑回归) 概述

Logistic regression (逻辑回归)是当前业界比较常用的机器学习方法,用于估计某种事物的可能性.比如某用户购买某商品的可能性,某病人患有某种疾病的可能性,以及某广告被用户点击的可能性等.(注意这里是:“可能性”,而非数学上的“概率”,logisitc回归的结果并非数学定义中的概率值,不可以直接当做概率值来用.该结果往往用于和其他特征值加权求和,而非直接相乘) 那么它究竟是什么样的一个东西,又有哪些适用情况和不适用情况呢?   一.官方定义: , Figure 1. The log