舞蹈链 —— M × M 数独模板

数独为M × M,则有M × M × M行 、M × M × 4列
下面是数独题任意大小模板:

#include<bits/stdc++.h>
using namespace std;

const int M=16;	// 数独大小
const int MN=M*M*M+10;
const int MM=M*M*4+10;
const int MNN=MN*4+MM;	// 最大点数,数独问题节点没有那么多

struct DLX {
	int n,m,si;	// n行数m列数si目前有的节点数
	int U[MNN],D[MNN],L[MNN],R[MNN],Row[MNN],Col[MNN];
	int H[MN],S[MM];	// 记录行的选择情况和列的覆盖情况
	int ansd,ans[MN];
	void init(int _n,int _m) {	// 初始化空表
		n=_n;m=_m;
		for(int i=0; i<=m; i++) {	// 初始化第一横行(表头)
			S[i]=0;U[i]=D[i]=i;L[i]=i-1;R[i]=i+1;        
		}
		R[m]=0;L[0]=m;si=m;                 
		for(int i=1; i<=n; i++) H[i]=-1;
	}
	void link(int r,int c) {  
		++S[Col[++si]=c];Row[si]=r;
		D[si]=D[c];U[D[c]]=si;U[si]=c;D[c]=si;
		if(H[r]<0) H[r]=L[si]=R[si]=si;
		else {
			R[si]=R[H[r]];L[R[H[r]]]=si;
			L[si]=H[r];R[H[r]]=si;
		}
	}
	void remove(int c) {	//列 表中删掉c列
		L[R[c]]=L[c];R[L[c]]=R[c];
		for(int i=D[c]; i!=c; i=D[i])
			for(int j=R[i]; j!= i; j=R[j]) 
				U[D[j]]=U[j],D[U[j]]=D[j],--S[Col[j]];
	}
	void resume(int c) {	// 恢复c列
		for(int i=U[c]; i!=c; i=U[i])
			for(int j=L[i]; j!=i; j=L[j])
				++S[Col[U[D[j]]=D[U[j]]=j]];
		L[R[c]]=R[L[c]]=c;
	}
	bool dance(int d) { 
		if(R[0]==0) { ansd=d;return 1; }
		int c=R[0];
		for(int i=R[0]; i!=0; i=R[i])if(S[i]<S[c])c=i;
		remove(c);
		for(int i=D[c]; i!=c; i=D[i]) {
			ans[d]=Row[i];
			for(int j=R[i]; j!= i; j=R[j]) remove(Col[j]);
			if(dance(d+1)) return 1;
			for(int j=L[i]; j!=i; j=L[j]) resume(Col[j]);
		}
		resume(c); return 0;
	}
	void place(int &r,int &c1,int &c2,int &c3,int &c4,int i,int j,int k) {
		r=(i*M+j)*M+k;
		c1=M*M*0+i*M+j+1;
		c2=M*M*1+i*M+k;
		c3=M*M*3+j*M+k;
		c4=M*M*2+((i/4)*4+(j/4))*M+k;//确定第几个小九宫(16宫?),九宫4改3
	}
} dlx;

char ss[M+5][M+5];

int main() {
	int ca=0;
	while(scanf("%s",ss[0])!=EOF) {
		for(int i=1; i<M; i++)
			scanf("%s",ss[i]);
		dlx.init(M*M*M,M*M*4);
		int r,c1,c2,c3,c4;
		for(int i = 0; i < M; i++)
			for(int j = 0; j < M; j++)
				for(int k = 1; k <= M; k++)
					if(ss[i][j] == '-' || ss[i][j] == 'A'+k-1) {
						dlx.place(r,c1,c2,c3,c4,i,j,k);
						dlx.link(r,c1);
						dlx.link(r,c2);
						dlx.link(r,c3);
						dlx.link(r,c4);
					}
		dlx.dance(0);
		int v,x,y;
		for(int i=0; i<dlx.ansd; i++) {
			v=(dlx.ans[i]-1)%M;
			x=(dlx.ans[i]-1)/M/M;
			y=(dlx.ans[i]-1)/M%M;
			ss[x][y]=v+'A';
		}
		if(ca++) printf("\n");
		for(int i=0; i<M; i++) printf("%s\n",ss[i]);
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值