zoukankan      html  css  js  c++  java
  • 【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;
    }
    


  • 相关阅读:
    Android权限 uses-permission
    Android中的颜色设置
    px 与 dp, sp换算公式?
    如何成为一名黑客?(转)
    uva 1291(dp)
    框架模式 MVC 在Android中的使用
    CCA概述和安装
    机房收费系统合作版(三)——UI思索
    (36)JS运动之使物体向右运动
    二叉查找树的非递归操作
  • 原文地址:https://www.cnblogs.com/claireyuancy/p/6862071.html
Copyright © 2011-2022 走看看