您的位置:首页 > 其它

dlx 精确覆盖

2012-10-11 21:43 176 查看
dlx的合集比赛点击这里
hust

poj 3074 标准数独模版

#include <cstdio>
#include <cstring>
/**
在计算科学理论中,这一类问题的解答被称之为NPC问题中的Hitting Set Problem,中文名应该叫做碰集问题。
该类问题可以通过转换成为精确覆盖问题,其中以行表示概然,以列表示常规约束。
在数独问题中,行所表示的概然状态很明显为(r,c,k)即行,列,放置的数字。而列所表示的约束大致整理了下,
分做四种,即r行中放置数k可行性,c列放置数k可行性,放置于(r,c)格子可行性以及块b(即所属区域)放置数k的可行性。
因此行总共有N*N*N=9*9*9=729个,列总共有9*9*4=324个,问题转化为在729*324的矩阵中取若干行,使每个列只有一个'1',
此时对应一个数独的解,而(r,c)格的约束保证了我们最后解的行数一定<=N*N。至此,模型转化完成。
**/
const int maxn=100000+123;
const int maxc=1000+5;

int S[maxc], L[maxn], R[maxn], D[maxn], U[maxn];
int H[maxc], ok[maxc], sz, C[maxn], mark[maxn];
///H是横向的表头, 不知道必不必要
void Link(int row, int col){
S[col]++; C[sz]=col;///C域指向列头
U[sz]=U[col]; D[U[col]]=sz;
D[sz]=col; U[col]=sz;

if(H[row]==-1)H[row]=L[sz]=R[sz]=sz;
else{
L[sz]=L[H[row]]; R[L[H[row]]]=sz;
R[sz]=H[row]; L[H[row]]=sz;
}
mark[sz]=row;/// 标记每个点是哪一行(题目要求输出解属于哪一行)
sz++;
}

void remove(int col)
{
L[R[col]]=L[col];
R[L[col]]=R[col]; /// 在列对象链表中删除col
for (int i=D[col]; i!=col; i=D[i]){/// 删除col列中有1元素的行
for (int j=R[i]; j!=i; j=R[j]){///删除每行的1元素,并修改所在列的S域
U[D[j]]=U[j], D[U[j]]=D[j];
S[C[j]]--;
}
}
}

void resume(int col){
for (int i=U[col]; i!=col; i=U[i]){
for (int j=L[i]; j!=i; j=L[j]){
U[D[j]]=j; D[U[j]]=j;
S[C[j]]++;
}///恢复删除的元素,恢复S域
}///恢复删除的行
L[R[col]]=col;
R[L[col]]=col;
}

bool Dance(int k){
if(R[0]==0){
char ans[100];
for (int i=0; i<k; ++i){
ans[(ok[i]-1)/9]=(ok[i]-1)%9+1+'0';
}
ans[k]=0;
puts(ans);
return true;
}
int c=R[0];
for(int i=R[0]; i; i=R[i])
if(S[i]<S[c])c=i;
remove(c);
for(int i=D[c]; i!=c; i=D[i]){
ok[k]=mark[i];
for (int j=R[i]; j!=i; j=R[j])
remove(C[j]);
if(Dance(k+1))return true;
for (int j=L[i]; j!=i; j=L[j])
resume(C[j]);
}
resume(c);
return false;
}

void initL(int x){
for (int i=0; i<=x; ++i){
S[i]=0;
D[i]=U[i]=i;
L[i+1]=i; R[i]=i+1;
}///对列表头初始化
R[x]=0;
sz=x+1;///真正的元素从m+1开始
memset (H, -1, sizeof(H));
///mark每个位置的名字
}
const int m=9*9*4;
const int n=9*9*9;
int main()
{/// 1~81:row col  82~162:row k 163~243:col k 244~324:block k
char str[100];
while(~scanf("%s", str)){
if(str[0]=='e')break;
initL(m);
for (int i=0; i<9; ++i){
for (int j=0; j<9; ++j){
int pos=i*9+j;
if(str[pos]=='.'){
for (int k=1; k<=9; ++k){
int row=pos*9+k;
Link(row, pos+1);
int col=81+i*9+k;
Link(row, col);
col=81*2+j*9+k;
Link(row, col);
col=81*3+((i/3)*3+j/3)*9+k;
Link(row, col);
}
}
else {
int k=str[pos]-'0';
int row=pos*9+k;
Link(row, pos+1);
int col=81+i*9+k;
Link(row, col);
col=81*2+j*9+k;
Link(row, col);
col=81*3+((i/3)*3+j/3)*9+k;
Link(row, col);
}
}
}
Dance(0);
}
return 0;
}


poj 3076 16*16数独 代码不贴了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: