您的位置:首页 > 其它

Sudoku (DLX 算法)

2015-06-22 19:37 204 查看
用DLX来解决16*16 数独问题。
#include <iostream>
#include<stdio.h>
#include<cmath>
#include<string.h>
#include<algorithm>
#include<string>
#include<vector>
using namespace std;
const int maxn = 2010;
const int maxnode = 20010;
const int maxr = 5010;
struct DLX
{
int n,sz; // 列数,节点总数
int S[maxn];  //各列节点数

int row[maxnode],col[maxnode];   //各节点行列标号
int L[maxnode],R[maxnode],U[maxnode],D[maxnode];  // 十字链表 记录节点ID

int ansd,ans[maxr];   //解

void init(int n)
{
this->n=n;

//虚拟节点
for(int i=0;i<=n;i++)
{
U[i]=i,D[i]=i,L[i]=i-1,R[i]=i+1;
}
R
=0,L[0]=n;

sz=n+1;
memset(S,0,sizeof S);
}

void addrow(int r,vector<int>columns)   //添加一行
{
int first=sz;
for(int i=0;i<(int)columns.size();i++)
{
int c=columns[i];
L[sz]=sz-1;R[sz]=sz+1;D[sz]=c,U[sz]=U[c];
D[U[c]]=sz;U[c]=sz;
row[sz]=r;col[sz]=c;
S[c]++;sz++;
}

R[sz-1]=first,L[first]=sz-1;
}
#define FOR(i,A,s) for(int i=A[s];i!=s;i=A[i])
void remove(int c)
{
L[R[c]]=L[c];
R[L[c]]=R[c];
FOR(i,D,c)
FOR(j,R,i)
{
U[D[j]]=U[j];
D[U[j]]=D[j];
--S[col[j]];
}
}
void restore(int c)
{
FOR(i,U,c)
FOR(j,L,i)
{
++S[col[j]];
U[D[j]]=j;
D[U[j]]=j;
}
L[R[c]]=c;
R[L[c]]=c;
}

bool dfs(int d)
{
if(R[0]==0)
{
ansd=d;              //找到了解
return 1;
}
//找到S最小的列c
int c=R[0];               //第一个为删除的列
FOR(i,R,0)
if(S[i]<S[c])
c=i;

remove(c);
FOR(i,D,c)
{
ans[d]=row[i];
FOR(j,R,i) remove(col[j]);
if(dfs(d+1)) return 1;
FOR(j,L,i) restore(col[j]);
}
restore(c);

return 0;
}
bool solve(vector<int> &v)
{
v.clear();
if(!dfs(0)) return 0;
for(int i=0;i<ansd;i++)
v.push_back(ans[i]);
return 1;
}
};
DLX sudoku;
struct Sel
{
int r,c,v;
}S[maxr];
char G[20][20];
int get_id(int x,int y)
{
return 4*(x/4)+y/4;
}
void add(int id,int r,int c,int v)
{
vector<int>x;
x.push_back(16*r+c+1);
x.push_back(16*16+16*r+v+1);
x.push_back(16*16*2+16*c+v+1);
x.push_back(16*16*3+16*get_id(r,c)+v+1);
sudoku.addrow(id,x);

}
int main()
{
int ca=0;
while(~scanf("%s",G[0]))
{
if(ca)
puts("");
ca++;
for(int i=1;i<16;i++)
scanf("%s",G[i]);
sudoku.init(1024);
int cnt=1;
for(int i=0;i<16;i++)
{
for(int j=0;j<16;j++)
{
if(G[i][j]=='-')
{
for(int k=0;k<16;k++)
{
S[cnt].r=i;
S[cnt].c=j;
S[cnt].v=k;
add(cnt,i,j,k);
cnt++;
}
}
else
{
S[cnt].r=i;
S[cnt].c=j;
S[cnt].v=G[i][j]-'A';
add(cnt,i,j,G[i][j]-'A');
cnt++;
}
}
}
vector<int>ans;
ans.clear();
sudoku.solve(ans);
for(int i=0;i<ans.size();i++)
{
int tmp=ans[i];
G[S[tmp].r][S[tmp].c]=S[tmp].v+'A';
}

for(int i=0;i<16;i++)
printf("%s\n",G[i]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: