题目链接:
朴素算法:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int sc[10][10]={{0,0,0,0,0,0,0,0,0,0},
{0,6,6,6,6,6,6,6,6,6},
{0,6,7,7,7,7,7,7,7,6},
{0,6,7,8,8,8,8,8,7,6},
{0,6,7,8,9,9,9,8,7,6},
{0,6,7,8,9,10,9,8,7,6},
{0,6,7,8,9,9,9,8,7,6},
{0,6,7,8,8,8,8,8,7,6},
{0,6,7,7,7,7,7,7,7,6},
{0,6,6,6,6,6,6,6,6,6}};
int po[10][10]={{0,0,0,0,0,0,0,0,0,0},
{0,1,1,1,2,2,2,3,3,3},
{0,1,1,1,2,2,2,3,3,3},
{0,1,1,1,2,2,2,3,3,3},
{0,4,4,4,5,5,5,6,6,6},
{0,4,4,4,5,5,5,6,6,6},
{0,4,4,4,5,5,5,6,6,6},
{0,7,7,7,8,8,8,9,9,9},
{0,7,7,7,8,8,8,9,9,9},
{0,7,7,7,8,8,8,9,9,9}};
int q,ms,t,s;
int a[10][10];bool h[10][10],z[10][10],b[10][10];
int ds[83][2];
void dfs(int d,int sco)
{
int i,j,Ii;
//if (t==10000000) return;t++;
if (d==0)
{
if (sco>ms) ms=sco;
return;
}
i=ds[d][0],j=ds[d][1];
for (Ii=1;Ii<=9;Ii++)
if (h[i][Ii]&&z[j][Ii]&&b[po[i][j]][Ii])
{
h[i][Ii]=false;z[j][Ii]=false;b[po[i][j]][Ii]=false;
dfs(d-1,sco+sc[i][j]*Ii);
h[i][Ii]=true;z[j][Ii]=true;b[po[i][j]][Ii]=true;
}
}
int main()
{
q=0;ms=0;t=0;s=0;
memset(h,1,sizeof(h));
memset(z,1,sizeof(z));
memset(b,1,sizeof(b));
for (int i=1;i<=9;i++)
for (int j=1;j<=9;j++)
{ int x;
scanf("%d",&x);
a[i][j]=x;
if (x!=0)
{
h[i][x]=false;
z[j][x]=false;
b[po[i][j]][x]=false;
s+=x*sc[i][j];
} else
{
q++;
ds[q][0]=i;
ds[q][1]=j;
}
}
dfs(q,s);
if (ms==0)printf("-1\n");
else printf("%d",ms);
return 0;
}
DLX:
#include<iostream>
#include<cstdio>
#define INT_MAX 10000000
#define MR 9*9*9
#define MC 9*9*4
using namespace std;
int Left[MC+MR*9]; //左边的元素
int Right[MC+MR*9]; //右边的元素
int Up[MC+MR*9]; //下边的元素
int Down[MC+MR*9]; //上边的元素
int S[MC]; //列标元素
int hang[MC+MR*9]; //所在行
int lie[MC+MR*9]; //所在列
int head[10][10][10];
int count;
int map[10][10];
int result[10][10];
int best=-1,SCORE=0;
int score[10][10]=
{
{0,0,0,0,0,0,0,0,0,0},
{0,6,6,6,6,6,6,6,6,6},
{0,6,7,7,7,7,7,7,7,6},
{0,6,7,8,8,8,8,8,7,6},
{0,6,7,8,9,9,9,8,7,6},
{0,6,7,8,9,10,9,8,7,6},
{0,6,7,8,9,9,9,8,7,6},
{0,6,7,8,8,8,8,8,7,6},
{0,6,7,7,7,7,7,7,7,6},
{0,6,6,6,6,6,6,6,6,6}
};
void init();
int getg(int i,int j);
void insert(int c,int count); //插入节点
void del(int c); //暂时删除
void res(int c); //恢复节点
void dfs(int k); //开始深搜
int main()
{
init();
for (int i=0;i<=81*4;i++) //初始化
{
S[i]=0;
Left[i]=i-1; Right[i]=i+1;
Up[i]=Down[i]=i;
lie[i]=0;
}
Left[0]=81*4; Right[81*4]=0;
count=81*4;
for (int i=1;i<=9;i++)
for (int j=1;j<=9;j++)
{
if (map[i][j]) //处理已占用的格子
{
int k=map[i][j];
for (int u=1;u<=4;u++)
{
Left[count+u]=count+u-1;
Right[count+u]=count+u+1;
hang[count+u]=100*i+10*j+k;
}
Left[count+1]=count+4;
Right[count+4]=count+1;
head[i][j][k]=count+1;
//cout<<head[i][j][k]<<endl;
insert((i-1)*9+j,count+1);
insert(81+(i-1)*9+k,count+2);
insert(81*2+(j-1)*9+k,count+3);
insert(81*3+(getg(i,j)-1)*9+k,count+4);
count+=4;
// cout<<count<<endl;
}
else //处理未占用的格子
for (int k=1;k<=9;k++)
{
for (int u=1;u<=4;u++)
{
Left[count+u]=count+u-1;
Right[count+u]=count+u+1;
hang[count+u]=100*i+10*j+k;
}
Left[count+1]=count+4;
Right[count+4]=count+1;
head[i][j][k]=count+1;
//cout<<head[i][j][k]<<endl;
insert((i-1)*9+j,count+1);
insert(81+(i-1)*9+k,count+2);
insert(81*2+(j-1)*9+k,count+3);
insert(81*3+(getg(i,j)-1)*9+k,count+4);
count+=4;
//cout<<count<<endl;
}
}
int k=0;
for (int i=1;i<=9;i++) //先加上已有的格子的得分
for (int j=1;j<=9;j++)
if (map[i][j])
{
k++;
SCORE+=(map[i][j])*score[i][j];
del(lie[head[i][j][map[i][j]]]);
for (int u=Right[head[i][j][map[i][j]]];u!=head[i][j][map[i][j]];u=Right[u])
del(lie[u]);
}
dfs(k+1);
printf("\n%d\n",best);
for (int i=1;i<10;i++)
{
for (int j=1;j<10;j++) cout<<result[i][j]<<" ";
cout<<endl;
}
return 0;
}
void init()
{
for (int i=1;i<=9;i++)
for (int j=1;j<=9;j++)
scanf("%d",&map[i][j]); //输入元素
}
int getg(int i,int j)
{
i--;
j--;
return (i/3)*3+(j/3+1); //获得宫数
}
void insert(int c,int count) //插入节点
{
Up[Down[c]]=count;
Down[count]=Down[c];
Up[count]=c;
Down[c]=count;
S[c]++;
lie[count]=c;
}
void del(int c) //暂时删除
{
Left[Right[c]]=Left[c]; //删左右
Right[Left[c]]=Right[c];
for (int i=Down[c];i!=c;i=Down[i]) //删一列
for (int j=Right[i];j!=i;j=Right[j]) //列中所有元素所在的行
{
Up[Down[j]]=Up[j];
Down[Up[j]]=Down[j];
S[lie[j]]--;
}
}
void res(int c) //恢复节点
{
for (int i=Up[c];i!=c;i=Up[i]) //逐行恢复
for (int j=Left[i];j!=i;j=Left[j])
{
Up[Down[j]]=Down[Up[j]]=j;
S[lie[j]]++;
}
Left[Right[c]]=Right[Left[c]]=c; //左右接起来
}
void dfs(int k) //开始深搜
{
if (k>81)
{
cout<<endl;
for (int i=1;i<10;i++)
{
for (int j=1;j<10;j++) cout<<map[i][j]<<" ";
cout<<endl;
}
if (SCORE>best)
{
best=SCORE;
for (int i=1;i<10;i++)
for (int j=1;j<10;j++)
result[i][j]=map[i][j];
}
return;
}
int c,minnum=INT_MAX;
for (int i=Right[0];i!=0;i=Right[i]) //从个数最小的开始(启发式思想)
{
if (!S[i]) return;
if (S[i]<minnum)
{
minnum=S[i];
c=i;
}
}
del(c); //删除列。
for (int i=Down[c];i!=c;i=Down[i]) //枚举每一个
{
int tmp=hang[i];
SCORE=SCORE+(tmp%10)*(score[tmp/100][(tmp/10)%10]);
map[tmp/100][(tmp/10)%10]=tmp%10;
for (int j=Right[i];j!=i;j=Right[j])
del(lie[j]);
dfs(k+1);//下一层
SCORE=SCORE-(tmp%10)*(score[tmp/100][(tmp/10)%10]);//回溯
map[tmp/100][(tmp/10)%10]=0;
for (int j=Left[i];j!=i;j=Left[j])
res(lie[j]);
}
res(c);
}