august 发表于 2007-10-6 23:45:38

C程序题

新年晚会老师给大家分糖,手端着一盘糖,让第一个同学先拿1块糖,再把盘中的糖分1/7给他;然后让第二个同学拿2块糖,再把盘中的糖的1/7给他;第三个同学拿3块糖后,仍把盘中的糖的1/7给他。照这个办法分下去,最后一个同学自己拿完糖后,糖恰好分完,而且每个人分到的糖块数相同。问共有几人?每人分几块糖?

由“最后一个同学自己拿完糖后,糖恰好分完”以及前面的条件可知,最后一个同学所拿的糖的数量刚好等于人数。

这个题应该怎么编写呢?

august 发表于 2007-10-7 02:16:33

main()
      {int t=0,m,n,i,j;
      for (m=6;!t;m+=6)      --------> 这里M为什么以6开始???
      {t=1;n=m;                  /*n为最后一个同学所拿到的糖的数量(即
                  人数),t=1假设当前n满足条件*/
      for (i=m-1;(i>=1)&&t;i--)
      {j=n/6+i;                /*第i个同学分到的糖的数量*/------>为什么这里等于第I个的数量呢?
      n=n/6*7+i;            /*第i个同学分到糖之前所剩的糖的数量*/
      if (j!=m) t=0;          /*每个人分到的糖块数相同.不满足就退
                  出模拟过程对人数重新取值*/
          }
    }
   printf ("%6d%6d\\n",m-6,m-6);
}
看到这样的解答 实在是不太看得懂

rednaxela 发表于 2007-10-7 03:16:39

我觉得...这题既然是让计算机算的,能不动人脑就不动人脑 (被拖走
好吧,不开玩笑,不过这题有十分多的高效解法.不可能全列出来.复杂的也不列出来,只说最直观的.

其中最短的就是纸笔推出数列通项,求和列一个一元方程.这个就算了.直接把答案输出出来就行 (死

再次,可以依靠"最后一个同学所拿的糖的数量刚好等于人数"+"每个人分到的糖块数相同"+"第n个人要先拿n块糖"来入手.这几个条件综合得知,假如总共有n人,那么最后一个同学(也就是第n个同学)要拿n块糖,同时糖已分完.进一步知道,每个同学拿到的糖数都是n块.所以糖的总数是n的平方.然后再把第一个同学所拿的糖拿来列一个一元二次方程...喂喂这不又直接求出答案了么.

所以,我们换种"蠢"一点的做法来玩玩.在分析得知糖的总数是人数的平方之后,我们就穷举所有大于1的正整数的平方作为糖数,按照最直观的方式去把糖"分配"下去,看看糖分到最后是否能正好分完.如下:

#include <stdio.h>

#define TRUE 1
#define FALSE 0

#define DIVISOR 7

typedef int bool;

bool dist( int ord, int remain ) {
    if ( remain == ord )
      return TRUE; /* 正确分完 */
    if ( remain < ord || remain % DIVISOR != ord )
      return FALSE; /* 不满足分配条件 */
   
    return dist( ord + 1, remain - ord - ( remain - ord ) / DIVISOR );
}

void main(void) {
    int person = 2;
    while ( dist( 1, person * person ) == FALSE )
      person++;
    printf( "%d", person );
}
其它的玩法还有很多...例如说可以完全无视上面的分析,硬把大于1的自然数穷举一遍,作为糖数扔进上面那递归函数去分析也可以,收敛速度会慢很多但这数字本来就小,看不出来的. = =
不用平方也不穷举,还可以通过第一个同学拿糖的情况,知道糖总数N肯定符合N = 7k + 1,其中k=1,2,3,4,...用这个条件扔进去检测也可以.
我上面的检测方法是直观的,正向的检查.反过来从最后一个同学开始检查也可以.
用递归也可以,用循环也可以.
总之办法多的是.

P.S. 其实按道理说只有1人,每人拿到1糖的结果也符合规律,只不过题目里已经出现了3,就假设人数大于等于3吧.这样在解一元二次方程的时候也可以扔掉一个解.

Have fun ^ ^

rednaxela 发表于 2007-10-7 03:46:27

LZ的代码一如既往难以阅读...

#include <stdio.h>

#define TRUE 1
#define FALSE 0

typedef int bool;

void main( void ) {
    int m, n, i, j;
    bool done = FALSE;
   
    for ( m = 6; !done; m += 6 ) { /* --------> 这里m为什么以6开始??? */
      done = TRUE;
      n = m;                  /* n为最后一个同学所拿到的糖的数量(即人数),done=TRUE假设当前n满足条件 */
      for ( i = m - 1; ( i >= 1 ) && done; i-- ) {
            j = n/6 + i;                /* 第i个同学分到的糖的数量 ------>为什么这里等于第i个的数量呢? */
            n = n/6*7 + i;            /* 第i个同学分到糖之前所剩的糖的数量*/
            if ( j != m )
                done = FALSE;          /* 每个人分到的糖块数相同.不满足就退出模拟过程对人数重新取值 */
      }
    }
    printf ("%6d%6d\\n", m-6, m-6);
}
建议LZ以后写好代码发出来之前先用astyle把代码格式化一次...

好吧LZ你要是是在书上看到这种解法的话,发email问它作者那m的意义你就明白了.是谁告诉你的就问谁吧,这代码 =_=||

august 发表于 2007-10-7 10:22:22

astyle是什么东东?

rednaxela 发表于 2007-10-7 10:39:16

没用过astyle也不知道是什么的话,请善用搜索引擎
http://astyle.sourceforge.net/
是一个美化/格式化代码的小工具.开源,免费.

lw 发表于 2007-10-7 13:19:02

代码整理VC内置的巴?
ASTYLE是什么………………

coolpay64 发表于 2007-10-7 16:27:41

某在eclipse已經解決格式的問題...用astyle的是vim達人吧
LZ的編程習慣還是有待改善...如果是某的同學,某C會好好調教的說...

這題如red君所言,還是先有數學式表達才真正編程
始終編程只是工具,沒有數學和邏輯編程是沒有意義的

rednaxela 发表于 2007-10-7 18:57:52

因为Eclipse的CDT在我自己上跑实在太慢,3.1和3.1.2之后我就再也没在Eclipse里用过CDT了.
JDT的话我确实是非常喜欢用Eclipse.代码格式化/重构/自动完成的功能相当不错.

推荐Astyle是因为不想假设别人用了什么IDE或者编辑器,所以推荐脱离IDE也能单独使用的格式化小工具嘛

woshijhl 发表于 2007-10-14 05:42:56

引用第1楼august于2007-10-07 02:16发表的:
main()
      {int t=0,m,n,i,j;
      for (m=6;!t;m+=6)      --------> 这里M为什么以6开始???
      {t=1;n=m;                  /*n为最后一个同学所拿到的糖的数量(即
                  人数),t=1假设当前n满足条件*/
.......
就是问为什么以6开始?这个简单啊...因为还剩余 6份啊 6/7嘛!
页: [1] 2
查看完整版本: C程序题