题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4069
★这题一开始题都看不懂,后来发现还是挺有意思的
题意:
给你一个9x9的矩阵, 矩阵里面有一些墙将数字划分为9个包含9个数字的宫 ,现在要问你能不能找到一种填数字的办法,使得矩阵的 每一行 每一列 每一宫 都包含9个不同的数字 。
而输入告诉你每个点的哪个方向有墙,输入中的81个数代表的意思是这样的:
如果这个数所在的单元没有墙,那这个数就是它本身,否则左边有墙就加128,下面有加64,右边有加32,上面有加16 比如第一个数144=128+16 故它所在的地方上面和左边有墙,而第二个数18=16+2即上面有墙值为2
思路:
玩过一般的数独,就是给一个9x9的矩阵,你要往里面填数字,必须满足哪些行、列包含1至9的所有数字。
但这题加了点难度,我写的上一题是划分为9个小3*3的方阵,这题是9个形状变化的宫。
但其实也还好,我们只要先找到那些单元在哪些宫就好了。这里通过BFS解决,DFS好像也可以吧
BFS
广搜前先记录下哪些单元的哪些方向有墙,有墙当然不走那个方向。然后就基本上是普通的BFS了。
void bfs(int x,int y,int c) //x y即坐标 c就是所在的宫id 从1到9
{
queue<point> q;
vis[x][y]=1;
p[x][y].plc=c;
point now=p[x][y];
q.push(now);
while(q.size()){
now=q.front();
q.pop();
for(int i=0;i<4;i++){ //四个方向
if(!now.d[i]){ //没墙可走
int xx=now.x+D[i][0];
int yy=now.y+D[i][1];
if(!vis[xx][yy]){ //没被标记过
vis[xx][yy]=1;
p[xx][yy].plc=c;
q.push(p[xx][yy]);
}
}
}
}
}
DLX
然后剩下的基本是DLX求数独的老套路了,以每个点放什么数为行 最多81x9行 ,以每个点放了没(1-81)、每一行放了什么数(82-162)、每一列放了什么数(163-243)、每一宫放了什么数(244-324)为列
就是在dance的时候稍稍修改,判断如果有两个答案就直接return ;
代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
using namespace std;
const int N=81*9*81*4+5;
const int M=81*9+5;
const int inf=0x7fffffff;
const int mod=1e9+7;
const double eps=1e-8;
const double pi=acos(-1);
typedef long long LL;
template<class T>
void read(T &x)
{
char c; x=1;
while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
T res=c-'0';
while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
x*=res;
}
int D[4][2]={{0,-1},{1,0},{0,1},{-1,0}}; //left down right up
struct DLX
{
int n,m,cnt,num;
int up[N],right[N],left[N],down[N];
int col[N],head[M],sz[M];
int test[N],get[N][3],ans[N];
void init(int nn,int mm)
{
n=nn; m=mm;
num=0;
for(int i=0;i<=m;i++){
up[i]=down[i]=i;
left[i]=i-1;
right[i]=i+1;
sz[i]=0;
}
cnt=m;
left[0]=m; right[m]=0;
for(int i=1;i<=n;i++) head[i]=-1;
}
void link(int r,int c,int x,int y,int v)
{
cnt++;
col[cnt]=c;
sz[c]++;
up[cnt]=up[c];
down[cnt]=c;
down[up[c]]=cnt;
up[c]=cnt;
get[cnt][0]=x; get[cnt][1]=y; get[cnt][2]=v;
if(head[r]==-1) head[r]=left[cnt]=right[cnt]=cnt;
else{
int tmp=head[r];
right[cnt]=tmp;
left[cnt]=left[tmp];
right[left[tmp]]=cnt;
left[tmp]=cnt;
}
}
void Remove(int c)
{
right[left[c]]=right[c];
left[right[c]]=left[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];
sz[col[j]]--;
}
}
}
void Resume(int c)
{
right[left[c]]=left[right[c]]=c;
for(int i=up[c];i!=c;i=up[i]){
for(int j=right[i];j!=i;j=right[j]){
up[down[j]]=down[up[j]]=j;
sz[col[j]]++;
}
}
}
void dance(int dep)
{
// cout<<dep<<endl;
if(right[0]==0&&dep==81){
num++;
for(int i=0;i<81;i++) ans[i]=test[i];
return ;
}
if(right[0]==0||num>=2) return ;
int now=right[0];
for(int i=now;i!=0;i=right[i]){
if(sz[i]<sz[now]) now=i;
}
Remove(now);
for(int i=down[now];i!=now;i=down[i]){
test[dep]=i;
for(int j=right[i];j!=i;j=right[j]) Remove(col[j]);
dance(dep+1);
if(num>=2) return ;
for(int j=left[i];j!=i;j=left[j]) Resume(col[j]);
}
Resume(now);
}
}dlx;
struct point
{
int x,y,plc,val; //(x,y),place,value
int d[4]; //direction
}p[10][10];
bool vis[10][10];
void bfs(int x,int y,int c)
{
queue<point> q;
vis[x][y]=1;
p[x][y].plc=c;
point now=p[x][y];
q.push(now);
while(q.size()){
now=q.front();
q.pop();
for(int i=0;i<4;i++){
if(!now.d[i]){
int xx=now.x+D[i][0];
int yy=now.y+D[i][1];
if(!vis[xx][yy]){
vis[xx][yy]=1;
p[xx][yy].plc=c;
q.push(p[xx][yy]);
}
}
}
}
}
void hhh(int x,int y,int v,int &s)
{
s++;
int p1=(x-1)*9+y; //(x,y) 放过了
int p2=(x-1)*9+v+81; //x行放了数字v
int p3=(y-1)*9+v+81*2; //y列放了数字v
int p4=(p[x][y].plc-1)*9+v+81*3; //宫plc放过了数字v
dlx.link(s,p1,x,y,v);
dlx.link(s,p2,x,y,v);
dlx.link(s,p3,x,y,v);
dlx.link(s,p4,x,y,v);
}
int main()
{
int t;
read(t);
int cas=0;
while(t--){
memset(p,0,sizeof p);
for(int i=1;i<=9;i++){
for(int j=1;j<=9;j++){
read(p[i][j].val);
p[i][j].x=i; p[i][j].y=j;
if(p[i][j].val>=128){ //there is a wall on left
p[i][j].val-=128;
p[i][j].d[0]=1;
}
if(p[i][j].val>=64){ //there is a wall on down
p[i][j].val-=64;
p[i][j].d[1]=1;
}
if(p[i][j].val>=32){ //there is a wall on right
p[i][j].val-=32;
p[i][j].d[2]=1;
}
if(p[i][j].val>=16){ //there is a wall on up
p[i][j].val-=16;
p[i][j].d[3]=1;
}
}
}
int cnt=0;
memset(vis,0,sizeof vis);
for(int i=1;i<=9;i++){
for(int j=1;j<=9;j++){
if(!vis[i][j]){
bfs(i,j,++cnt);
}
}
}
cnt=0;
int pp=0;
dlx.init(81*9,81*4);
for(int i=1;i<=9;i++){
for(int j=1;j<=9;j++){
if(p[i][j].val==0){
pp++;
for(int k=1;k<=9;k++)
hhh(i,j,k,cnt);
}
else hhh(i,j,p[i][j].val,cnt);
}
}
dlx.dance(0);
printf("Case %d:\n",++cas);
if(dlx.num==0) cout<<"No solution\n";
else if(dlx.num==2) cout<<"Multiple Solutions\n";
else{
int res[10][10];
for(int i=0;i<81;i++){
int t=dlx.ans[i];
int x=dlx.get[t][0];
int y=dlx.get[t][1];
int v=dlx.get[t][2];
res[x][y]=v;
}
for(int i=1;i<=9;i++){
for(int j=1;j<=9;j++){
cout<<res[i][j];
}
cout<<endl;
}
}
}
return 0;
}