九宫格C语言递归程序,[置顶] C语言递归实现N宫格(九宫格)源码

刚开始做九宫格的时候,能想到的就是几个for循环,很清楚很简单,同样也比较的低级,了解递归的魅力后,在高人的指点下,原来也可以这样的实现,写到这时,让我想到了当年教我们的老师,thanx,好代码,我还留着呢,我把当年写的源码分享一下,欢迎拍砖

如果有更好的方法,也可交流一下。。。。。。。

/**************************************************************************************************************

**文件:mian.c

**编写者:huangminqiang

**编写日期:2011年3月12号

**简要描述:递归实现N宫格(九宫格)

**修改者:

**修改日期:

**注:N>5后,运行结果需要的时间很长,适用于4-9-16宫格。

**************************************************************************************************************/

#include

#define N   4  //每行或列的数的个数

#define MAX   (N*N) //最大数

#define ROW_END  1  //行结束标志

#define COL_END  2  //列结束标志

#define LEFT_DOWN 3  //左下角标志

#define RIGHT_DOWN 4  //右下角标志

#define OTHER  0  //其它情况标志

//定义N宫格结构体

struct _ngg

{

int num[MAX];  //定义填数的数组

int val;   //判断相等的值

int count;   //符合条件的组合数

};

//函数原型声明

//初始化结构体变量

void init(struct _ngg *pngg);

//开始填数

void fill(struct _ngg * pngg,int pos);

//获取标志

int getFlag(int pos);

//判断某个数在之前是否已填过,已填过则返回 1 ,否则返回 0

int isFilled(struct _ngg * pngg,int pos,int i);

//计算行和

int sumRow(struct _ngg * pngg,int pos);

//计算列和

int sumCol(struct _ngg * pngg, int pos);

//计算左上-右下对角和

int sumLU_RD(struct _ngg * pngg);

//计算右上-左下对角和

int sumRU_LD(struct _ngg * pngg);

//打印数组

void prt(struct _ngg * pngg);

//主函数,初始化并开始按位置填数

int main(void)

{

//变量声明

struct _ngg ngg = {0};

//初始化结构体变量

init(&ngg);

printf("N = %d, MAX = %d, val = %d\n",N,MAX,ngg.val);

//开始填数

fill(&ngg,0);

return 0;

}

//初始化结构体变量

void init(struct _ngg *pngg)

{

//计算val的值

pngg->val = MAX * (MAX + 1) / 2 / N;

}

//子函数实现填数

void fill(struct _ngg * pngg,int pos)

{

//声明变量

int flag = getFlag(pos);  //结束标志

int i;

//从 1 到 MAX 逐个填入数组的 pos  位置

for(i = 1; i <=MAX; i++)

{

//判断 i 在前面有没有填过,填过则填下一个数

if(isFilled(pngg,pos,i))

{

continue;

}

//填入 i 到 pos 位置

pngg->num[pos] = i;

//根据 flag 分情况进行处理

switch(flag)

{

//行结束

case ROW_END:

//如果行和相等则继续填下一个位置

if(pngg->val == sumRow(pngg,pos))

{

fill(pngg,pos+1);

}

break;

//列结束

case COL_END:

//如果列和相等则继续填下一个位置

if(pngg->val == sumCol(pngg,pos))

{

fill(pngg,pos+1);

}

break;

//左下角

case LEFT_DOWN:

//如果列和、右上-左下对角和相等则填下一个位置

if(pngg->val == sumCol(pngg,pos) &&

pngg->val == sumRU_LD(pngg))

{

fill(pngg,pos+1);

}

break;

//右下角

case RIGHT_DOWN:

//如果行和、列和、左上-右下对角和相等则打印数组

if(pngg->val == sumRow(pngg,pos) &&

pngg->val == sumCol(pngg,pos) &&

pngg->val == sumLU_RD(pngg) )

{

prt(pngg);

}

break;

//其它情况

//case OTHER:

default:

//其它情况填下一个位置

fill(pngg,pos+1);

}

}

}

//获取标志

int getFlag(int pos)

{

//如果到了行尾,但不是最后一个元素则为行结束

if(0 == (pos + 1) % N && MAX - 1 != pos)

{

return ROW_END;

}

//如果到了列尾,但不是第 0 列,也不是最后一个元素,则为列结束

if(pos > N * (N - 1) && MAX - 1 != pos)

{

return COL_END;

}

//如果是最后一行,并且是第 0 列,则为左下角

if(pos == N * (N - 1))

{

return LEFT_DOWN;

}

//如果是最后一个元素,则是右下角

if(MAX - 1 == pos)

{

return RIGHT_DOWN;

}

//除此之外是其它情况

return OTHER;

}

//判断某个数在之前是否已填过,已填过则返回 1 ,否则返回 0

int isFilled(struct _ngg * pngg,int pos,int i)

{

int j;

for(j = 0; j < pos;j++)

{

if(pngg->num[j] == i)

{

return 1;

}

}

return 0;

}

//计算行和

int sumRow(struct _ngg * pngg,int pos)

{

int i,sum = 0;

//从第 pos 个元素往回加

for(i = pos; i > pos - N; i--)

{

sum += pngg->num[i];

}

return sum;

}

//计算列和

int sumCol(struct _ngg * pngg, int pos)

{

int i,sum = 0;

//从第 pos 个元素往上加

for(i = pos; i >= 0; i -= N)

{

sum += pngg->num[i];

}

return sum;

}

//计算右上-左下对角和

int sumRU_LD(struct _ngg * pngg)

{

int i,sum = 0;

//从第 N - 1 个元素开始每次跳过 N - 1 个元素累加

for(i = N - 1; i < MAX -1; i += N - 1)

{

sum += pngg->num[i];

}

return sum;

}

//计算左上-右下对角和

int sumLU_RD(struct _ngg * pngg)

{

int i,sum = 0;

//从第 0 个元素开始每次跳过 N + 1个元素累加

for(i = 0; i < MAX; i += N + 1)

{

sum += pngg->num[i];

}

return sum;

}

//打印数组

void prt(struct _ngg * pngg)

{

int i;

printf("-----------------------------------------%d\n",++pngg->count);

for(i = 0; i < MAX; i++)

{

printf("\t%d",pngg->num[i]);

if(0 == (i + 1) % N)

{

printf("\n");

}

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值