'''
1、确保不出现连续两次only=2的情况
2、只要做了only=2的试填,就压入Stack
做only=1不压入栈!!
3、出现报错,立刻退栈,再错再退,直到退回第一次only=2的尝试
疑问:1、退档是否要退a b A B ans的所有档?
退档的具体操作:
先出栈,上一次only=2的尝试,将另外一个数字填入即可(即转化成only=1的情况),别的都不用管
'''from copy import deepcopy
from time import clock
start = clock()#f(x)函数的作用是,输入一组数据,返回1-9间的补集deff(x):
ans =[]for i inrange(1,10):if i notin x:
ans.append(i)return ans
#用于检测是否出现数字重复,即报错defcheck(x,b,C):
flag =Falsefor i inrange(1,10):for j in x:if j.count(i)>1:
flag =Truebreakfor i inrange(1,10):for j in b:if j.count(i)>1:
flag =Truebreakfor i inrange(1,10):for m in C:for n in m:if n.count(i)>1:
flag =Truebreakif flag==True:return"Error"else:return"True"
stack_x =[]
stack_a =[]
stack_b =[]
stack_A =[]
stack_B =[]
stack_ans =[]
stack_M =[]#表示每次做only=2的尝试是,ans的行列
stack_N =[]#数独是9*9的二维数组a,输入空的用0表示#先尝试获取输入,x表示最原始的数独
x =[[None,None,None,None,None,None,None,None,None],[None,None,None,None,None,None,None,None,None],[None,None,None,None,None,None,None,None,None],[None,None,None,None,None,None,None,None,None],[None,None,None,None,None,None,None,None,None],[None,None,None,None,None,None,None,None,None],[None,None,None,None,None,None,None,None,None],[None,None,None,None,None,None,None,None,None],[None,None,None,None,None,None,None,None,None],]#输入数独
num =0while num!=9:
line =raw_input()
k=-1for i in line:
k+=1
x[num][k]=int(i)
num +=1
change =False#change指针用于指示是否将ans插入'x'whileTrue:#import copy模块的deepcopy复制数组#a数组共有9行,表示每行已经存在的数字0
a = deepcopy(x)#去掉所有的0再次存入afor i in a:whileTrue:if0in i:
i.remove(0)else:break#b数组是输入的置换矩阵,即行列交换
b =[[None,None,None,None,None,None,None,None,None],[None,None,None,None,None,None,None,None,None],[None,None,None,None,None,None,None,None,None],[None,None,None,None,None,None,None,None,None],[None,None,None,None,None,None,None,None,None],[None,None,None,None,None,None,None,None,None],[None,None,None,None,None,None,None,None,None],[None,None,None,None,None,None,None,None,None],[None,None,None,None,None,None,None,None,None],]for i inrange(9):for j inrange(9):
b[i][j]=x[j][i]#去掉所有0再次存入bfor i in b:whileTrue:if0in i:
i.remove(0)else:break#A、B两个数组表示a、b的补集,再同C三者求交集便表示可能填的数字
A =[None,None,None,None,None,None,None,None,None]for i inrange(9):
A[i]=f(a[i])
B =[None,None,None,None,None,None,None,None,None]for i inrange(9):
B[i]=f(b[i])#尝试解决宫内重复的问题#c数组是3*3表示每个宫内的数字,去0再存入c
c =[[[None,None,None,None,None,None,None,None,None],[None,None,None,None,None,None,None,None,None],[None,None,None,None,None,None,None,None,None]],[[None,None,None,None,None,None,None,None,None],[None,None,None,None,None,None,None,None,None],[None,None,None,None,None,None,None,None,None]],[[None,None,None,None,None,None,None,None,None],[None,None,None,None,None,None,None,None,None],[None,None,None,None,None,None,None,None,None]]]
temp =[]for i inrange(3):for j inrange(3):
temp.append(x[i][j])for i inrange(9):
c[0][0][i]=temp[i]
temp =[]for i inrange(3):for j inrange(3,6):
temp.append(x[i][j])for i inrange(9):
c[0][1][i]=temp[i]
temp =[]for i inrange(3):for j inrange(6,9):
temp.append(x[i][j])for i inrange(9):
c[0][2][i]=temp[i]
temp =[]for i inrange(3,6):for j inrange(3):
temp.append(x[i][j])for i inrange(9):
c[1][0][i]=temp[i]
temp =[]for i inrange(3,6):for j inrange(3,6):
temp.append(x[i][j])for i inrange(9):
c[1][1][i]=temp[i]
temp =[]for i inrange(3,6):for j inrange(6,9):
temp.append(x[i][j])for i inrange(9):
c[1][2][i]=temp[i]
temp =[]for i inrange(6,9):for j inrange(3):
temp.append(x[i][j])for i inrange(9):
c[2][0][i]=temp[i]
temp =[]for i inrange(6,9):for j inrange(3,6):
temp.append(x[i][j])for i inrange(9):
c[2][1][i]=temp[i]
temp =[]for i inrange(6,9):for j inrange(6,9):
temp.append(x[i][j])for i inrange(9):
c[2][2][i]=temp[i]#去掉所有的0重新存入数组cfor i in c:for j in i:whileTrue:if0in j:
j.remove(0)else:break
C = deepcopy(c)
m=-1for i in c:
m+=1
n=-1for j in i:
n+=1
c[m][n]=f(j)#求交集方法,list( set(a) & set(b) & set(c) )#ans代表每个空可以输入的数字
ans =[[None,None,None,None,None,None,None,None,None],[None,None,None,None,None,None,None,None,None],[None,None,None,None,None,None,None,None,None],[None,None,None,None,None,None,None,None,None],[None,None,None,None,None,None,None,None,None],[None,None,None,None,None,None,None,None,None],[None,None,None,None,None,None,None,None,None],[None,None,None,None,None,None,None,None,None],[None,None,None,None,None,None,None,None,None]]for i inrange(9):for j inrange(9):if x[i][j]==0:
ans[i][j]=list(set(A[i])&set(B[j])&set(c[i/3][j/3]))else:
ans[i][j]=[]'''change指针为True,说明此处ans会导致连续两次的only=2,所以加'x'
'''if change==True:print'm,n:',stack_M[-1],stack_N[-1]print'x:',x[stack_M[-1]][stack_N[-1]]print'sdsadasdasdasd:',ans[stack_M[-1]][stack_N[-1]]iflen(ans[stack_M[-1]][stack_N[-1]])!=0:
ans[stack_M[-1]][stack_N[-1]].append('x')
change=False'''还要优先检测是否已经填了重复的数字,这是用ans无法检测出来的'''if check(x,b,C)=="Error":print"Error exists"#退到上一个二选一的Stack档,并且换数字,交换位置即可
a = stack_a.pop();b = stack_b.pop();
A = stack_A.pop();B = stack_B.pop();
M = stack_M.pop();N = stack_N.pop();
ans = stack_ans.pop();x = stack_x.pop();
ans[M][N].pop()print"after [Error] back stack x:"for i in x:print i
'''一定要优先检测ans是否报错,一旦报错立刻退档'''#如果ans中该填空为位置有空集,说明暴力填词出错,退档即可
m =-1for i in ans:
flag1 =False#flag1检测是否出现error,一旦出现立刻退档并且跳出for循环
m +=1
n =-1for j in i:
n +=1if x[m][n]==0and ans[m][n]==[]:#在应该填空的位置ans为空,就报错
flag1 =Trueprint"line "+str(m),"row "+str(n)+" Error exists!"#报错后立刻退档,退回上一个二选一
a = stack_a.pop();b = stack_b.pop();
A = stack_A.pop();B = stack_B.pop();
M = stack_M.pop();N = stack_N.pop();
ans = stack_ans.pop();x = stack_x.pop();#退回上一个only=2的情形,就将其自动变成only=1的ans空
ans[M][N].pop()#因为试填默认试第二个,所以直接pop即可breakif flag1==True:break#only表示只能填唯一数的空数#若only=0,则找到only=2的进行试填,直至再次出现only=1的情况
only =Falsefor i inrange(9):for j inrange(9):iflen(ans[i][j])==1:print"There exists only one condition!"print"only a["+str(i)+"]["+str(j)+"]="+str(ans[i][j][0])
only =Trueprint ans[i][j],"!!!!!!!!!"print x[i][j]
x[i][j]= ans[i][j][0]'''
重点,做暴力试填的点,要做全局变量标记,因为可能会退档
!!优化:优先选择填完Only=2后能产生Only=1的来优先Try,这就需要逐一去试,若不能产生Only=1就退档,再进入for寻找下一个Only=2的
'''
only2 =Falseif only ==False:print"No only=1 exists@@@"
flag2 =False
m =-1for i in ans:
m +=1
n =-1for j in i:
n +=1iflen(j)==2:
only2=True
stack_a.append(deepcopy(a));stack_b.append(deepcopy(b));stack_A.append(deepcopy(A));stack_B.append(deepcopy(B));stack_M.append(deepcopy(m));stack_N.append(deepcopy(n));stack_ans.append(deepcopy(ans));stack_x.append(deepcopy(x))
x[m][n]=ans[m][n][1]if check(x,b,C)=="Error":
x[m][n]=0#默认试填第二个数字(反正蒙中概率是50%)
flag2 =True#flag2表示是否有only=2的空,有的话立刻试填,并且所有数据入栈以作备份breakif flag2==True:break#Check检测是否还有0未填
Check =[]for i in x:for j in i:
Check.append(j)if0notin Check:#所有空已经填完,则跳出程序break#如果能跳出while,那么一定产生了答案(但未必是正确的答案) if check(x,b,C)=="True":print"answer:"for i in x:print i
else:print"Sorry I cannot @-@"
end = clock()printint(start)printint(end)print end-start