java数独.docx
- 文档编号:23629418
- 上传时间:2023-05-19
- 格式:DOCX
- 页数:15
- 大小:17.91KB
java数独.docx
《java数独.docx》由会员分享,可在线阅读,更多相关《java数独.docx(15页珍藏版)》请在冰豆网上搜索。
java数独
/******************************shudu.h*****************************/
#ifndef__SHUDU_H__
#define__SHUDU_H__
/*
*这是数独的节点结构体
*next和prev构成了一个双向循环链表
*clue是一个线索的指针,它用于记录删除后的节点
*并且回溯的实现也是依靠它
*/
structnode{
intnum;
structnode*next;
structnode*prev;
structnode*clue;
};
/*
*这是一个用于删除节点的宏
*删除sd,并且让它的头的num--;
*挂到head上
*但是没有free
*/
#defineDEL(sd,head)\
sd->clue->num--;\
sd->clue=head->clue;\
head->clue=sd;\
sd->prev->next=sd->next;\
sd->next->prev=sd->prev;
#endif
/*********************************shudu.c*****************************************/
#include"shudu.h"
#include
#include
voiddel_equal(structnode*sd,intnum,structnode*head){
/*
*删除sd这个头所挂的节点中,值与num相同的节点
*这里我直接用sd,而没有新创建一个指针
*/
sd=sd->next;
while(sd!
=sd->clue){
if(sd->num>num)break;/*因为节点是有序的*/
if(sd->num==num){
DEL(sd,head);
break;
}
sd=sd->next;
}
}
voiddel_unequal(structnode*sd,intnum,structnode*head){
/*
*删除sd这个头所挂的节点中,值与num不同的节点
*/
sd=sd->next;
while(sd!
=sd->clue){
if(sd->num!
=num){
DEL(sd,head);
}
sd=sd->next;
}
}
intis_invalid(structnodeshudu[][9],inti,intj){
/*判断合法不合法,不合法就返回-1,这里判断的一定是已经确定的点*/
intk,t;
for(k=0;k<9;k++){
if(shudu[i][k].num||k==j)continue;
if(shudu[i][k].next->num==shudu[i][j].next->num)return-1;//invalid
}
for(k=0;k<9;k++){
if(shudu[k][j].num||k==i)continue;
if(shudu[k][j].next->num==shudu[i][j].next->num)return-1;//invalid
}
for(k=i/3*3;k
for(t=j/3*3;t if(shudu[k][t].num||(k==i&&t==j))continue; if(shudu[k][t].next->num==shudu[i][j].next->num)return-1; } return0; } voidshudu_backtrace(structnodeshudu[][9],structnode*head){ /* *用于回溯的函数 *如果head->num是0应该不会到这,如果到了这,肯定是数独有问题 */ structnode*p=head->clue; structnode*p2; inti,j; if(! head->num){ printf("Thisisbadshudu! \n"); //理论上这应该销毁该销毁的,我就让系统帮我了 exit(-1); } /* *如果p->num! =0,也就是没到标记节点,那么就 *一直复原到标记节点 */ while(p->num){ p2=p->clue; p->next->clue->num++; p->next->prev=p; p->prev->next=p; p->clue=p->next->clue;//得让它的clue再指向它的头 head->clue=p2; p=p2; } DEL(p->prev,head);/*删除第一个节点,因为我们猜的第一个节点 猜错了才会到这,那么我们该选第二个了*/ /*下面就是把标记结点删掉,并且free了它*/ p->prev->clue=p->clue; free(p); p=NULL; head->num--;/*标记节点数--*/ /*这里也该shudu_clear,但是不知道i和j了,只能找一下了*/ for(i=0;i<9;i++){ for(j=0;j<9;j++){ if(&shudu[i][j]! =p2->next->clue)continue; shudu_clear(shudu,i,j,head); return; } } } intshudu_clear(structnodeshudu[][9],inti,intj,structnode*head){ /* *当有一个新的数字确定下来之后就调用这个函数 *这个函数会把当前行,列,块中与已确定数字冲突的数字清掉 *如果清掉后的数字也确定下来了,就递归调用该函数 */ intk,t; if(is_invalid(shudu,i,j)){ //printf("backtrace...\n"); shudu_backtrace(shudu,head); return-1; } /*这里(i,j)位置上的数应该已经确定*/ for(k=0;k<9;k++){ if(! shudu[i][k].num)continue;//如果这个数已经确定就跳过 del_equal(&shudu[i][k],shudu[i][j].next->num,head); if(! shudu[i][k].num) if(shudu_clear(shudu,i,k,head))return-1; } for(k=0;k<9;k++){ if(! shudu[k][j].num)continue;//如果这个数已经确定就跳过 del_equal(&shudu[k][j],shudu[i][j].next->num,head); if(! shudu[k][j].num) if(shudu_clear(shudu,k,j,head))return-1; } for(k=i/3*3;k for(t=j/3*3;t if(! shudu[k][t].num)continue;//如果这个数已经确定就跳过 del_equal(&shudu[k][t],shudu[i][j].next->num,head); if(! shudu[k][t].num) if(shudu_clear(shudu,k,t,head))return-1; } } return0; } intall_is_well(structnodeshudu[][9],structnode*head){ /* *判断整个数组是不是合法的,合法返回1 */ inti,j; for(i=0;i<9;i++){ for(j=0;j<9;j++){ if(! shudu[i][j].num){ if(is_invalid(shudu,i,j))return0; } } } return1; } voidshudu_show(structnodeshudu[][9]){ /*打印而已*/ inti,j; printf("+---------------------------+\n"); for(i=0;i<9;i++){ if(i==3||i==6)printf("\n"); for(j=0;j<9;j++){ if(j==3||j==6)printf(""); if(! shudu[i][j].num) printf("%d",shudu[i][j].next->num); elseprintf("[]"); } printf("\n"); } printf("+---------------------------+\n"); } voidshudu_init(structnodeshudu[][9],structnode*head){ inti,j,k; structnode*tmp; intnums[9][9]={ /*这个是号称全球最难的数独*/ #if1 8,0,0,0,0,0,0,0,0, 0,0,3,6,0,0,0,0,0, 0,7,0,0,9,0,2,0,0, 0,5,0,0,0,7,0,0,0, 0,0,0,0,4,5,7,0,0, 0,0,0,1,0,0,0,3,0, 0,0,1,0,0,0,0,6,8, 0,0,8,5,0,0,0,1,0, 0,9,0,0,0,0,4,0,0, #endif /*0,0,8,0,0,0,2,0,0, 0,3,0,8,0,2,0,6,0, 7,0,0,0,9,0,0,0,5, 0,5,0,0,0,0,0,1,0, 0,0,4,0,0,0,6,0,0, 0,2,0,0,0,0,0,7,0, 4,0,0,0,8,0,0,0,6, 0,7,0,1,0,3,0,9,0, 0,0,1,0,0,0,8,0,0, */ #if0 0,0,1,0,0,0,6,0,0, 0,5,9,0,0,2,0,0,0, 4,0,0,0,0,6,0,0,2, 0,0,0,8,7,0,0,1,0, 2,0,0,0,9,0,0,0,7, 0,4,0,0,5,3,0,0,0, 8,0,0,5,0,0,0,0,6, 0,0,0,1,0,0,7,9,0, 0,0,4,0,0,0,5,0,0, #endif #if0 0,0,0,0,3,0,0,0,0, 0,8,0,9,0,5,0,6,0, 4,0,7,0,0,0,3,0,9, 0,0,0,1,0,3,0,0,0, 0,6,0,0,4,0,0,1,0, 0,0,0,8,0,6,0,0,0, 9,0,2,0,0,0,6,0,7, 0,7,0,4,0,8,0,9,0, 0,0,0,0,9,0,0,0,0, #endif }; #if0 printf("Pleaseinput9x9numbers: \n"); printf("forexample: \n"); printf(" 800000000\n"); printf(" 003600000\n"); printf(" 070090200\n"); printf(" 050007000\n"); printf(" 000045700\n"); printf(" 000100030\n"); printf(" 001000068\n"); printf(" 008500010\n"); printf(" 090000400\n"); /* *我就不在这里判断你输入的是什么东西了 */ for(i=0;i<9;i++){ printf(": "); fflush(0); for(j=0;j<9;j++){ scanf("%d",&nums[i][j]); } } #endif head->clue=head; head->num =0;/*这个用作记录标记节点的个数吧*/ head->prev=head; head->next=head; for(i=0;i<9;i++){ for(j=0;j<9;j++){ shudu[i][j].num=8;/*代表了它下面挂有的节点数 如果为0,代表只挂有一个数 只挂有一个数就是这个数已经确定*/ shudu[i][j].next=&shudu[i][j]; shudu[i][j].prev=&shudu[i][j]; shudu[i][j].clue=&shudu[i][j]; /* *这里创建9个节点,挂在shudu[i][j]下 */ for(k=0;k<9;k++){ tmp=(structnode*)malloc(sizeof(structnode)); tmp->clue=&shudu[i][j];/*都指向头*/ tmp->num =9-k;//1~9 /*前插法*/ tmp->next=shudu[i][j].next; tmp->prev=&shudu[i][j]; tmp->prev->next=tmp; tmp->next->prev=tmp; } } } for(i=0;i<9;i++){ for(j=0;j<9;j++){ if(! nums[i][j])continue; del_unequal(&shudu[i][j],nums[i][j],head);/*删除与nums[i][j]不同的*/ shudu_clear(shudu,i,j,head);/*把冲突的清掉*/ } } } intis_only(structnodeshudu[][9],inti,intj,intnum){ /* *判断(i,j)这个位置num是不是可以放在这 *也就是说,这一行中所有没有确定下来的格中 *num是不是唯一的,如果是唯一的,就应该返回1 *当然一列,一块这三个有一个num是唯一的就应该返回1 */ intk,t; structnode*p; intnr=3; for(k=0;k<9;k++){ if(! shudu[i][k].num||k==j)continue; p=shudu[i][k].next; while(p! =p->clue){ if(p->num==num){ nr--; gotoout1; } if(p->num>num)break; p=p->next; } } out1: for(k=0;k<9;k++){ if(! shudu[k][j].num||k==i)continue; p=shudu[k][j].next; while(p! =p->clue){ if(p->num==num){ nr--; gotoout2; } if(p->num>num)break; p=p->next; } } out2: for(k=i/3*3;k for(t=j/3*3;t if(! shudu[k][t].num||(k==i&&t==j))continue; p=shudu[k][t].next; while(p! =p->clue){ if(p->num==num){ nr--; gotoout3; } if(p->num>num)break; p=p->next; } } out3: if(nr)return1; return0; } intfilter(structnodeshudu[][9],structnode*head){ /* *过滤函数 *在所有没有确定的位置的数有了可以唯一确定的了 *就del_unequal并且shudu_clear */ inti,j; structnode*p; for(i=0;i<9;i++) for(j=0;j<9;j++){ if(! shudu[i][j].num)continue; p=shudu[i][j].next; while(p! =p->clue){ if(is_only(shudu,i,j,p->num)){ del_unequal(&shudu[i][j],p->num,head); if(shudu_clear(shudu,i,j,head))return-1; return1; } p=p->next; } } return0; } inttry_do(structnodeshudu[][9],structnode*head){ /* *当已经没有可以确定的数的时候会调用这个函数 *这个函数会找一个有两种情况的位置先猜一个 *当然这里首先创建了一个标记节点,它的num==0 */ inti,j; structnode*tmp; for(i=0;i<9;i++){ for(j=0;j<9;j++){ if(shudu[i][j].num! =1)continue;//两种情况的 //printf("trydo...\n"); tmp=(structnode*)malloc(sizeof(structnode)); tmp->num=0; tmp->clue=head->clue;/*先把tmp挂到head上*/ head->clue=tmp; tmp->prev=shudu[i][j].next;/*tmp的prev指向了第一个*/ tmp->next=tmp->prev->next;/*tmp的next指向了第二个*/ DEL(tmp->next,head);/*删了第二个,也就是我们猜了第一个*/ head->num++;/*让标记节点的数目++*/ /*别忘了要shudu_clear一下*/ if(shudu_clear(shudu,i,j,head))return-1; return1; } } /* *如果已经成功了,那么返回,如果现在最少的情况也是3种情况,那我也无能为力了, *不过我觉的这情况很少,号称最难的数独也有一个2种情况的 */ return0; } voidshudu_run(structnodeshudu[][9],structnode*head){ /* *运行函数 *不管filter返回是1还是-1,都应该继续循环 *返回0的话就是已经没有可以确定的了,那么 *只能try_do了,如果try_do也返回0那就是真该结束了 */ do{ while(filter(shudu,head)); }while(try_do(shudu,head)); /*判断一下对不对*/ if(all_is_well(shudu,head))printf("Yes,Itis! \n"); elseprintf("No,error! \n"); } voidshudu_destroy(structnodeshudu[][9],structnode*head){ /* *统一销毁 */ inti,j; structnode*p; p=head->clue; while(p! =head){ head->clue=p->clue; free(p); p=head->clue; } p=NULL; for(i=0;i<9;i++){ for(j=0;j<9;j++){ free(shudu[i][j].next); } } } intmain(intargc,char**argv){ structnodeshudu[9][9]; structnodehead;//cluehead shudu_init(shudu,&head); shudu_run(shudu,&head); shudu_show(shudu); shudu_destroy(shudu,&head); return0; }
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- java