3074 - Sudoku

算法dlx。下面只讲如何建模。
就是一个729*324的矩阵。
行数:数独共有81格,每个有9种数可填,∴81*9=729
列数:数独每格只能填一次(81格),每行、每列、每个九宫格内有且仅有九种数(3*9*9),∴81+3*9*9=324
然后将读进来的数所对应的行都删去,跑一遍精确覆盖,然后重新加入这些行。
反正思路是这样的。下面的代码还没调出来,千万不要看!
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define rep(i,j,k) for(i=j;i<=k;++i)
#define per(i,j,k) for(i=j;i>=k;--i)
#define ll long long
#define db double
#define mkp(x,y) make_pair(x,y)
#define pii pair<int,int>
#define X first
#define Y second
const int N=729,M=324,NM=250000;
struct DLX{
	int L[NM],R[NM],U[NM],D[NM],ro[NM],co[NM],H[N+1],S[M+1],cnt,sz,ans[82];//H为行首,S为每列元素个数 
	void reset(){
		int i;rep(i,0,M)
			S[i]=0,L[i]=i-1,R[i]=i+1,U[i]=D[i]=i;
		L[0]=M,R[M]=0,sz=M+1;
		memset(H,-1,sizeof H);
	}
	void ins(int x,int y){
		++S[co[sz]=y],ro[sz]=x;//确定所在行、列 
		U[D[sz]=D[y]]=sz;
		U[D[y]=sz]=y;//将sz插入y和D[y]中
		if(H[x]<0)H[x]=L[sz]=R[sz]=sz;
		else{
			L[R[sz]=R[H[x]]]=sz;
			R[L[sz]=H[x]]=sz;
		}//将sz插入H[x]和R[H[x]]中
		++sz; 
	}
	void init(){
		int i,j,k,x;
		rep(i,1,9)rep(j,1,9)rep(k,1,9){
			x=(i-1)*81+(j-1)*9+k;
			ins(x,(i-1)*9+j),ins(x,81+(i-1)*9+k),ins(x,162+(j-1)*9+k),ins(x,243+((i-1)/3*3+(j-1)/3)*9+k);
		}
	}
	void del(int c){
		R[L[R[c]]=L[c]]=R[c];
		int i,j;
		for(i=D[c];i!=c;i=D[i])
			for(j=R[i];j!=i;j=R[j])
				D[U[D[j]]=U[j]]=D[j],--S[co[j]];
	}
	void add(int c){
		R[L[c]]=L[R[c]]=c;
		int i,j;
		for(i=U[c];i!=c;i=U[i])
			for(j=L[i];j!=i;j=L[j])
				++S[co[U[D[j]]=D[U[j]]=j]];
	}
	bool DFS(){
		if(!R[0])return 1;
		int c,i,j;
		for(i=c=R[0];i;i=R[i])if(S[c]>S[i])c=i;//找出元素最多的一列 
		del(c);
		for(i=D[c];i!=c;i=D[i]){
			for(j=R[i];j!=i;j=R[j])del(co[j]);
			ans[(ro[i]-1)/9]=(ro[i]-1)%9+1;
			if(DFS())return 1;
			for(j=L[i];j!=i;j=L[j])add(co[j]);
		}
		add(c);
		return 0;
	}
	void solve(string s){
		int tmp[81],i,x,y;
		memset(ans,0,sizeof ans);
		rep(i,0,80)if(s[i]!='.'){
			ans[i+1]=s[i]-'0';
			del(co[x=H[tmp[i]=9*(i+1)+ans[i+1]]]);
			for(y=R[x];y!=x;y=R[y])del(co[y]);
		}
		DFS();
		rep(i,0,80)if(s[i]!='.'){
			add(co[x=H[tmp[i]]]);
			for(y=R[x];y!=x;y=R[y])add(co[y]);
		}
		rep(i,1,81)printf("%d",ans[i]);
	}
}dlx;
int main(){
	string s;
	dlx.reset();dlx.init();
	while(1){
		cin>>s;
		if(s=="end")break;
		dlx.solve(s);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值