1. 程式人生 > >【POJ3074】Sudoku DLX(Dancing Links)

【POJ3074】Sudoku DLX(Dancing Links)

puts struct pre i++ 能夠 ring include 為什麽 處理

數獨就要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;
}


【POJ3074】Sudoku DLX(Dancing Links)