QQ 1423173783 EMAIL 1423173783@qq.com 欢迎提出不同意见//如果数组a改为人工输入或从文件中读取。S[]可用程序计算 数组N[]这里没用是代码只要求输出那几行覆盖了所有列,如果代码要求哪一行覆盖了哪几列,它就能派上用场
//代码有个特点,用数组模拟了双向十字链表,时间复杂度不知道是变好了还是变坏了。
//双向十字链表,有列头没行头,这是可以改进的,我有预感,数独中是需要行头的。此代码用来求所有解,要遍历所有情况。
#include<iostream>
#include<cstdlib>
using namespace std;
int a[7][8]= {0,0,0,0,0,0,0,0,
0,0,0,1,0,1,1,0,
0,1,0,0,1,0,0,1,
0,0,1,1,0,0,1,0,
0,1,0,0,1,0,0,0,
0,0,1,0,0,0,0,1,
0,1,1,1,1,1,1,1};
int U[100]={0},D[100]={0},R[100]={0},L[100]={0},S[8]={0,3,3,3,3,2,3,3},O[6]={0};
void remove(int 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[j%10]--;
}
}
void resume(int c)
{
for(int i=U[c];i!=c;i=U[i])
for(int j=L[i];j!=i;j=L[j])
{
U[D[j]]=j;
D[U[j]]=j;
S[j%10]++;
}
L[R[c]]=c;
R[L[c]]=c;
}
void DFS(int k)
{
if(!R[0])
{
for(int i=0;i<=5;i++)
{cout<<O[i]<<" "; O[i]=0;}
cout<<endl;
return;
}
int count=100,c;
for(int i=R[0];i;i=R[i])
if(S[i]<count)
{
count=S[i];
c=i;
if(count==1) break;
}
remove(c);
for(int i=D[c];i!=c;i=D[i])
{
O[k]=i/10;
for(int j=R[i];j!=i;j=R[j])
remove(j%10);
DFS(k+1);
for( int j=L[i];j!=i;j=L[j])
resume(j%10);
}
resume(c);
}
int main()
{
char N[9]="1ABCDEFG";
int row,col;
for(col=0;col<=7;col++)
{
L[col]=col-1;
R[col]=col+1;
}
L[0]=7; R[7]=0;
for(row=0;row<=6;row++)//在这个exact cover 中是用不到的 但在sudoku中能用到
{
U[row]=row-1;
D[row]=row+1;
}
U[0]=6; D[6]=0;
for(col=1;col<=7;col++)
{
int tmp[2]={0};
row=1;
while(a[row][col]==0)
{ row++; } ;
tmp[0]=row; tmp[1]=col;
D[col]=10*row+col;
U[10*row+col]=col;
for(int i=row+1;i<=6;i++)
if(a[i][col]==0) continue;
else
{
D[10*tmp[0]+tmp[1]]=10*i+col;
U[10*i+col]=10*tmp[0]+tmp[1];
tmp[0]=i; tmp[1]=col;
}
D[10*tmp[0]+tmp[1]]=col;
U[col]=10*tmp[0]+tmp[1];
}
for(row=1;row<=6;row++)
{
int tmp[2]={0};
col=1;
while(a[row][col]==0)
{ col++; } ;
tmp[0]=row; tmp[1]=col;
int col8=col;
for(int i=col+1;i<=7;i++)
if(a[row][i]==0) continue;
else
{
R[10*tmp[0]+tmp[1]]=10*row+i;
L[10*row+i]=10*tmp[0]+tmp[1];
tmp[0]=row; tmp[1]=i;
}
R[10*tmp[0]+tmp[1]]=10*row+col8;
L[10*row+col8]=10*tmp[0]+tmp[1];
}
DFS(0);
system("pause");
}
//此题是exact cover的一个特例的解法,如果数组a改为人工输入或从文件中读取。S[]可用程序计算 数组N[]这里没用是代码只要求输出那几行覆盖了所有列,如果代码要求哪一行覆盖了哪几列,它就能派上用场
//代码有个特点,用数组模拟了双向十字链表,时间复杂度不知道是变好了还是变坏了。
//双向十字链表,有列头没行头,这是可以改进的,我有预感,数独中是需要行头的。此代码用于求一个解就跳出不遍历所有情况。
#include<iostream>
#include<cstdlib>
using namespace std;
int a[7][8]= {0,0,0,0,0,0,0,0,
0,0,0,1,0,1,1,0,
0,1,0,0,1,0,0,1,
0,0,1,1,0,0,1,0,
0,1,0,0,1,0,0,0,
0,0,1,0,0,0,0,1,
0,1,1,1,1,1,1,1};
int U[100]={0},D[100]={0},R[100]={0},L[100]={0},S[8]={0,3,3,3,3,2,3,3},O[6]={0};
void remove(int 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[j%10]--;
}
}
void resume(int c)
{
for(int i=U[c];i!=c;i=U[i])
for(int j=L[i];j!=i;j=L[j])
{
U[D[j]]=j;
D[U[j]]=j;
S[j%10]++;
}
L[R[c]]=c;
R[L[c]]=c;
}
bool DFS(int k)
{
if(!R[0]) return(true);
int count=100,c;
for(int i=R[0];i;i=R[i])
if(S[i]<count)
{
count=S[i];
c=i;
if(count==1) break;
}
remove(c);
for(int i=D[c];i!=c;i=D[i])
{
O[k]=i/10;
for(int j=R[i];j!=i;j=R[j])
remove(j%10);
if(DFS(k+1)) return (true);
for( int j=L[i];j!=i;j=L[j])
resume(j%10);
}
resume(c);
return(false);
}
int main()
{
char N[9]="1ABCDEFG";
int row,col;
for(col=0;col<=7;col++)
{
L[col]=col-1;
R[col]=col+1;
}
L[0]=7; R[7]=0;
for(row=0;row<=6;row++)//在这个exact cover 中是用不到的 但在sudoku中能用到
{
U[row]=row-1;
D[row]=row+1;
}
U[0]=6; D[6]=0;
for(col=1;col<=7;col++)
{
int tmp[2]={0};
row=1;
while(a[row][col]==0)
{ row++; } ;
tmp[0]=row; tmp[1]=col;
D[col]=10*row+col;
U[10*row+col]=col;
for(int i=row+1;i<=6;i++)
if(a[i][col]==0) continue;
else
{
D[10*tmp[0]+tmp[1]]=10*i+col;
U[10*i+col]=10*tmp[0]+tmp[1];
tmp[0]=i; tmp[1]=col;
}
D[10*tmp[0]+tmp[1]]=col;
U[col]=10*tmp[0]+tmp[1];
}
for(row=1;row<=6;row++)
{
int tmp[2]={0};
col=1;
while(a[row][col]==0)
{ col++; } ;
tmp[0]=row; tmp[1]=col;
int col8=col;
for(int i=col+1;i<=7;i++)
if(a[row][i]==0) continue;
else
{
R[10*tmp[0]+tmp[1]]=10*row+i;
L[10*row+i]=10*tmp[0]+tmp[1];
tmp[0]=row; tmp[1]=i;
}
R[10*tmp[0]+tmp[1]]=10*row+col8;
L[10*row+col8]=10*tmp[0]+tmp[1];
}
DFS(0);
for(int i=0;i<=5;i++)
cout<<O[i]<<" ";
cout<<endl;
system("pause");
}