关于手机数字类游戏的探索(一)续*行列皆递增数组矩阵 *说明: *对于给定的行列方阵 *矩阵应满足:每一行递增,每一列递增。 *数据最小为1,最大为个数。 求出所有满足条件的排列组合并输出。 *例:1--> 2 1--> 3 * | | | | * V V V V * 3--> 4 及 2--> 4 是2行2列的行列递增方阵 * 箭头(下箭头不知道怎么表示就用V了)所示为递增方向 */ #include <stdio.h> #include <conio.h>//getch(); #include <assert.h> #define N 3//方阵大小,因为C中不能用a[n][m] #define M 3//方阵大小,所以只好这样啦 #define LEN N*M #define MIN 0 #define MAX LEN+1 /*求解*/ bool SearchSolutionSet();//n 是方阵行数,m方阵列数 /*从位置posx,posy开始往后求解*/ bool SearchFromPos(int ptrArr[N+2][M+2],//指针:存储方阵数据 int posx, //在列方向上的计数 int posy,//在行方向上的计数 int flagused[LEN+1]//数字使用状态 ); /*判定当前数num能否放在posx,posy位置*/ bool IsPossible(int ptrArr[N+2][M+2], int posx, int posy, int num); /*输出方阵*/ bool OutPut(int ptrArr[N+2][M+2]); /*用于调试的函数*/ void OutPutDebug(int flagused[LEN+1]);//用于Debug,输出数字使用状态 /*------------------------------------------------------------------------------------*/ int count=0; //记录解个数 int num=0; //Debug用,查看递归次数 /*------------------------------------------------------------------------------------*/ /* IN:行,列数 * OUT:true 有解,false 无解*/ /*求解*/ bool SearchSolutionSet()//n 是方阵行数,m方阵列数 { count=0; //记录解个数 int ptrArr[N+2][M+2]={0};//申请空间存储方阵,带边界 int flagused[LEN+1]={0};//flag[i]=ture;数i被使用//flag[i]=flase;数i未被使用 for(int i=0;i<N+2;i++) for(int j=0;j<M+2;j++) if(i==0||j==0)//初始化,只有当i=0的行,j=0列是最小值边界 ptrArr[i][j]=MIN; else ptrArr[i][j]=MAX;//其它为MAX bool isSoluable=false; //有无解标记;false : 无 ,ture :有 isSoluable=SearchFromPos(ptrArr, 1, 1, flagused); return isSoluable; } /*从位置posx,posy开始往后求解*/ bool SearchFromPos(int ptrArr[N+2][M+2],//指针:存储方阵数据 int posx, //在列方向上的计数 int posy,//在行方向上的计数 int flagused[LEN+1]//数字使用状态 ) { assert(ptrArr!=NULL); ++num; int useable[LEN]={0};//记录当前所有可用数 // 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][1]=1; flagused[1]=1; ptrArr[N][M]=LEN; flagused[LEN]=1; flagsoluable=SearchFromPos(ptrArr, 2, 1, flagused); printf("/n返回,总次数%d./n",num); return flagsoluable;//出口点,返回有无解 } for(int i=2;i<LEN;i++)//查找标记,记录可用数目,并放入可用数组 if(flagused[i]==0) { useable[cnuseable]=i; cnuseable++; } // printf("有%d个可用数:/n",cnuseable);//调试用 /* if(cnuseable==0)//到达最后一个点,一定是解//1.深度是LEN { count++; OutPut(ptrArr);//输出方阵 return true;//有解:返回上一层继续搜索 } */ switch(cnuseable) //2.深度是LEN-2(大大的减少了调用次数) { case 0:count++;OutPut(ptrArr);return true; case 1:count++;ptrArr[posy][posx]=useable[0];OutPut(ptrArr);return true; case 2:if(posx==2) { count++; ptrArr[posy][2]=useable[0]; ptrArr[posy+1][1]=useable[1]; OutPut(ptrArr); count++; ptrArr[posy][2]=useable[1]; ptrArr[posy+1][1]=useable[0]; OutPut(ptrArr); return true; } count++; ptrArr[posy][posx]=useable[0]; ptrArr[posy][posx+1]=useable[1]; OutPut(ptrArr); return true; default:break; } if(posx<0||posx>M||posy<0||posy>N)//这个条件会发生,但在前面cnuseable一定是0 return 0; //程序到不了这就会返回 for(i=0;i<cnuseable;i++)//进行可用数遍历 { curnum=useable[i]; if(IsPossible(ptrArr, posx, posy, curnum))//数curnum可以放 { ptrArr[posy][posx]=curnum;//放入当前数 flagused[curnum]=1;//更新标记 if((posx+1)%(M+1))//没到下一行 { nextposx= (posx+1)%(M+1);//下一位置的计算,对应于一维的映射 nextposy= posy; } else //到了下一行 { nextposx= 1; nextposy= (posy+1)%(N+1); } if(!flagsoluable)//只要有一个解就返回true; flagsoluable=SearchFromPos(ptrArr, nextposx, nextposy, flagused);//放下一位置 else SearchFromPos(ptrArr, nextposx, nextposy, flagused); //返回点; ptrArr[posy][posx]=MAX; flagused[curnum]=0;//当前路径当前数已做解处理,释放标记 } //数curnum不能放,i++,进行下个可用数的判定。 } return flagsoluable;//返回可行状态 } /*------------------------------------------------------------------------------------*/ void OutPutDebug(int flagused[LEN+1])//输出数字使用情况 { 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[N+2][M+2]) { printf("/n第%d个解:/n",count); printf("/n"); for(int i=1;i<=N;i++) { if(i!=1) { for(int j=1;j<=M;j++) { printf("%-5.1s","|"); } printf("/n"); } for(int j=1;j<=M;j++) { if(ptrArr[i][j]<MAX) { printf("%-3d",ptrArr[i][j]); } else { printf("MAX"); } if(j!=M) { printf("->"); } } printf("/n"); } printf("/n当前调用%d次有解返回.",num); 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[N+2][M+2], int posx, int posy, int num) { if(num>=ptrArr[posy][posx+1]|| //比右大 num<=ptrArr[posy][posx-1]|| //比左小 num>=ptrArr[posy+1][posx]|| //比下大 num<=ptrArr[posy-1][posx]) //比上小 return false; else return true; } /*------------------------------------------------------------------------------------*/ int main() { // int n=3,m=3; /* printf("请输入数组大小n=行(>0),m=列(>0)!/n"); printf("n="); scanf("%d",&n); printf("/nm="); scanf("%d",&m); printf("/n"); 因为是用数组,所以要自己去改大小。 */ if(!SearchSolutionSet()) printf("/n很遗憾,你的水平太差!!。最小一个数。~~/n"); return 0; } /*------------------------------------------------------------------------------------*/ //欢迎指正,谢谢!!