2009-12-31 关于手机数字类游戏的探索(一) 如果看动态分配不爽就看续(另续中代码经过小点优化)。 /*关于手机数字类游戏的探索(一)。 *行列皆递增数组矩阵 *说明: *对于给定的行列方阵 *矩阵应满足:每一行递增,每一列递增。 *数据最小为1,最大为个数。 求出所有满足条件的排列组合并输出。 *例:1--> 2 1--> 3 * | | | | * V V V V * 3--> 4 及 2--> 4 是2行2列的行列递增方阵 * 箭头(下箭头不知道怎么表示就用V了)所示为递增方向 */ #include <stdio.h> #include <malloc.h>//用动态分配内存 #include <string.h>//用memset(,,); #include <conio.h>//getch(); #include <windows.h>//OutputDebugString(); #include <assert.h> /*求解*/ bool SearchSolutionSet(int n, int m);//n 是方阵行数,m方阵列数 /*从位置posx,posy开始往后求解*/ bool SearchFromPos(int * ptrArr,//指针:存储方阵数据 int posx, //在列方向上的计数 int posy,//在行方向上的计数 int *flagused//数字使用状态 ); /*从位置posx,posy开始往后清除数据(含此点),清除含义:赋值为边界值*/ bool CleanLaterPart(int *ptrArr, int row,//有效行数(不含边界) int col,//有效列数(不含边界) int posx, int posy, int *flagused); /*判定当前数num能否放在posx,posy位置*/ bool IsPossible(int * ptrArr, int posx, int posy, int num); /*输出方阵*/ bool OutPut(int *ptrArr, int row, int col); /*用于调试的函数*/ void OutPutDebug(int *flagused);//用于Debug,输出数字使用状态 /*------------------------------------------------------------------------------------*/ int min=0; //边界小值 int max=0; //边界大值 int row=0; //行,y坐标 int col=0; //列,x坐标 int count=0; //记录解个数 int len=0; //有用的数组长度(不含边界) int num=0; //Debug用,查看递归次数 /*------------------------------------------------------------------------------------*/ /* IN:行,列数 * OUT:true 有解,false 无解*/ /*求解*/ bool SearchSolutionSet(int n, int m)//n 是方阵行数,m方阵列数 { assert(n>0&&m>0); min=0; //边界小值为0 max=n*m+1;//最大数为n*m,让边界大值为n*m+1 row=n; col=m; count=0; //记录解个数 len=row*col; //有效长度 int * ptrArr=(int *)malloc((row+2)*(col+2)*sizeof(int));//申请空间存储方阵,带边界 int * flagused=(int *)malloc((len+1)*sizeof(int));//flag[i]=ture;数i被使用//flag[i]=flase;数i未被使用 for(int i=0;i<row+2;i++) for(int j=0;j<col+2;j++) if(i==0||j==0)//初始化,只有当i=0的行,j=0列是最小值边界 *(ptrArr+i*(col+2)+j)=min; else *(ptrArr+i*(col+2)+j)=max;//其它为MAX memset(flagused,0,(len+1)*sizeof(int));//初始标记0,全部可用 bool isSoluable=false; //有无解标记;false : 无 ,ture :有 isSoluable=SearchFromPos(ptrArr, 1, 1, flagused); free(flagused); flagused=NULL; free(ptrArr); ptrArr=NULL; return isSoluable; } /*从位置posx,posy开始往后求解*/ bool SearchFromPos(int * ptrArr,//指针:存储方阵数据 int posx, //在列方向上的计数 int posy,//在行方向上的计数 int *flagused//数字使用状态 ) { assert(ptrArr!=NULL); ++num; /* OutPut(ptrArr,row,col); printf("/n第%d次调用.",num);//调试用 OutPutDebug(flagused); */ int * useable=(int *)malloc(len*sizeof(int));//记录当前所有可用数 memset(useable,0,len*sizeof(int)); bool flagsoluable=false; int cnuseable=0; int nextposx=0; int nextposy=0; int curnum=0; if(posx==1&&posy==1)//入口点 { *(ptrArr+1*(col+2)+1)=1; *(flagused+1)=1; *(ptrArr+row*(col+2)+col)=len; *(flagused+len)=1; flagsoluable=SearchFromPos(ptrArr, 2, 1, flagused); printf("/n返回,总次数%d./n",num); free(useable); useable=NULL; return flagsoluable;//出口点,返回有无解 } for(int i=2;i<len;i++)//查找标记,记录可用数目,并放入可用数组 if(*(flagused+i)==0) { *(useable+cnuseable)=i; cnuseable++; } // printf("有%d个可用数:/n",cnuseable);//调试用 if(cnuseable==0)//到达最后一个点,一定是解 { count++; printf("/n第%d个解:/n",count); OutPut(ptrArr, row, col);//输出方阵 printf("/n当前调用%d次有解返回.",num); free(useable); useable=NULL; return true;//有解:返回上一层继续搜索 } if(posx<0||posx>col||posy<0||posy>row)//这个条件会发生,但在前面cnuseable一定是0 return 0; //程序到不了这就会返回 for(i=0;i<cnuseable;i++)//进行可用数遍历 { curnum=*(useable+i); //if(*(flagused+curnum)) continue;//不出意外,这个条件为假 if(IsPossible(ptrArr, posx, posy, curnum))//数curnum可以放 { *(ptrArr+posy*(col+2)+posx)=curnum;//放入当前数 *(flagused+curnum)=1;//更新标记 if((posx+1)%(col+1))//没到下一行 { nextposx= posx+1;//下一位置的计算,对应于一维的映射 nextposy= posy; } else //到了下一行 { nextposx= 1; nextposy= (posy+1)%(row+1); } if(!flagsoluable)//只要有一个解就返回true; flagsoluable=SearchFromPos(ptrArr, nextposx, nextposy, flagused);//放下一位置 else SearchFromPos(ptrArr, nextposx, nextposy, flagused); //返回点; *(ptrArr+posy*(col+2)+posx)=max; *(flagused+curnum)=0;//当前路径当前数已做解处理,释放标记 } //数curnum不能放,i++,进行下个可用数的判定。 } // 前面已做清除 // CleanLaterPart(ptrArr, row, col, posx, posy, flagused);//清除数组中在当前位置(含)之后的数据,以防下次赋值判定时有误 free(useable); useable=NULL; return flagsoluable;//返回可行状态 } /*------------------------------------------------------------------------------------*/ void OutPutDebug(int *flagused)//输出数字使用情况 { printf("/n当前数字使用情况:"); for(int i=1;i<len+1;i++) { printf("%3d=%3d ",i,*(flagused+i));//第i个标记=0:i可用;第i个标记=1:i不可用/已使用(如:第0个,第1个) } printf("/n"); } /*------------------------------------------------------------------------------------*/ /*输出方阵*/ bool OutPut(int *ptrArr, int row, int col) { printf("/n"); for(int i=1;i<=row;i++) { if(i!=1) { for(int j=1;j<=col;j++) { printf("%-5.1s","|"); } printf("/n"); } for(int j=1;j<=col;j++) { if(*(ptrArr+i*(col+2)+j)<max) { printf("%-3d",*(ptrArr+i*(col+2)+j)); } else { printf("MAX"); } if(j!=col) { printf("->"); } } printf("/n"); } char ch; if(count&&count%10==0) { printf("/n当前是否先等待:(Y/N)/n要退出等待继续请输入:N/n"); ch=getch(); if(ch=='Y'||ch=='y') { ch=getch(); while(ch!='N'||ch!='n') ch=getch(); } } return true; } /*------------------------------------------------------------------------------------*/ /*判定当前数num能否放在posx,posy位置*/ bool IsPossible(int * ptrArr, int posx, int posy, int num) { if(num>=*(ptrArr+posy*(col+2)+(posx+1))|| //比右大 num<=*(ptrArr+posy*(col+2)+(posx-1))|| //比左小 num>=*(ptrArr+(posy+1)*(col+2)+posx)|| //比下大 num<=*(ptrArr+(posy-1)*(col+2)+posx)) //比上小 return false; else return true; } /*从位置posx,posy开始往后清除数据(含此点);清除含义:赋值为边界值*/ bool CleanLaterPart(int *ptrArr, int row,//有效行数(不含边界) int col,//有效列数(不含边界) int posx, int posy, int *flagused) { printf("/nclean later part of the array!"); while(posy!=row||posx!=col) { *(ptrArr+posy*(col+2)+posx)=max; *(flagused+*(ptrArr+posy*(col+2)+posx))=0; if((posx+1)%(col+1)) { posx++; } else{ posx=1; posy++; } } return true; } /*------------------------------------------------------------------------------------*/ int main() { int n=3,m=3; /* printf("请输入数组大小n=行,m=列!/n"); printf("n="); scanf("%d",&n); printf("/nm="); scanf("%d",&m); printf("/n"); */ SearchSolutionSet(n,m); return 0; } /*------------------------------------------------------------------------------------*/