问题:

矩形的个数

  在一个3*2的矩形中,可以找到6个1*1的矩形,4个2*1的矩形3个1*2的矩形,2个2*2的矩形,2个3*1的矩形和1个3*2的矩形,总共18个矩形。给出A,B,计算可以从中找到多少个矩形

输入:
  本题有多组输入数据(<10000),你必须处理到EOF为止

  输入2个整数A,B(1<=A,B<=1000)

输出:

  输出找到的矩形数。

样例:

输入:

1 2
3 2

输出:
3
18

原代码-1:

#include <stdio.h>
int rectangle(int x,int y)
{
    int i,j,sum,temp;

    ,sum=,temp=;i<=x;i++)
    {
        ;j<=y;j++)
        {
            temp = (x-i+)*(y-j+);
            sum += temp;
        }
    }

    return sum;
}

int main()
{
    ],B[],i;
    int rectangle(int x,int y);
    //printf("input A&B and end with 0\n");

    ;i<;i++)
    {
        scanf("%d",&A[i]);

        )
        {
            break;
        }

        scanf("%d",&B[i]);
    }

    ;A[i]!=;i++)
    {
        printf("%d\n",rectangle(A[i],B[i]));
    }

    ;
}

评析:

  写完之后这位小朋友坦率地承认:

露珠不知道如何以EOF结尾..只好用0了...哪位指点下..

  我告诉他,

没必要用数组
while( scanf("%d%d", &A,&B)!=EOF )
{
     //计算输出矩形个数
}

  于是他很快给出了新代码:

原代码-2:

#include <stdio.h>
int rectangle(int x,int y)
{
    int i,j,sum,temp;

    ,sum=,temp=;i<=x;i++)
    {
        ;j<=y;j++)
        {
            temp = (x-i+)*(y-j+);
            sum += temp;
        }
    }

    return sum;
}

int main()
{
    long int A,B;
    int rectangle(int x,int y);
    printf("input A&B and end with EOF\n");

    while(scanf("%d%d",&A,&B)!= EOF)
    {
        printf("%d\n",rectangle(A,B));
    }

    ;
}

评析:

  这次好多了。不过他又有了新的困惑:

我修改成这样之后,比如我先输入 2 3 跳出来 18,输入eof 就一直跳 18 停止不了了...
总之就是一直跳最后一次出来的结果 ..

  看来他不清楚EOF是怎么回事,还以为是在键盘上键入eof三个字符呢。

  我告诉他:

EOF不是三个字符
而是一个符号常量
如果你用的是WIN系统
在行首输入Control-Z试试

  实际上EOF是在stdio.h中定义的一个宏,通常是这样的

#define    EOF    (-1)

  不过C语言并没说EOF一定为-1。

  在键盘上是没有这个EOF的,但在输入流中遇到特殊的字符,scanf()函数的返回值可以是EOF。那么,这句话究竟是什么意思呢?

  通常scanf()的返回值是一个非负整数。比如

int i;scanf("%d", &i ) ;

  如果你在键盘上键入的是123(1、2、3与%d相匹配),scanf("%d", &i )的值就为1,因为为1个变量赋了值;如果你在键盘上键的是abc(a与%d不匹配),scanf("%d", &i )的值就为0,因为scanf无法把"a"视为十进制整数(%d),也无法对它进行转换,更无法为变量 i 赋值,也就是说scanf这种情况下没有为任何变量赋值,所以返回值为0。如果scanf()在输入流中遇到的是某个特殊的字符(具体是哪个字符与环境有关),则返回值为EOF。

  另外我告诉他:

把函数类型声明
int rectangle(int x,int y);
写在main()函数之内很傻

(应该把函数类型声明)写在函数外面

另外那个temp多余

temp赋值为零就更多余

(因为可以直接)

sum += (x-i+1)*(y-j+1);   

  就这样,他再次进行了修改:

原代码-3

#include <stdio.h>
int rectangle(int x,int y)
{
    int i,j,sum,temp;

    ,sum=;i<=x;i++)
    {
        ;j<=y;j++)
        {
            sum += (x-i+)*(y-j+);;
        }
    }

    return sum;
}

int rectangle(int x,int y);
int main()
{
    long int A,B;
    printf("input A&B and end with EOF\n");

    while(scanf("%d%d",&A,&B)!= EOF)
    {
        printf("%d\n",rectangle(A,B));
    }

    ;
}

评析:

  现在毛病少多了,不过还是有一些。

  首先, rectangle()函数定义的位置不妥,写在main()定义的后面为好。

  其次,数据类型有问题,这个问题比较严重。

    long int A,B;

  这里绝对没有必要把A、B定义为long类型,int类型足矣。由于不当地把A、B定义成了long类型,所以代码中的

scanf("%d%d",&A,&B)

rectangle(A,B)

这两次调用都是错的。虽然没有产生错误的结果(估计在那个系统中long和int类型大小一样),但其实是瞎猫碰到死耗子,侥幸而已。

  此外的两处小瑕疵就是rectangle()函数定义中的temp变量忘记删除了,循环体内删除语句时不干净,有一“;”也忘记删除了。

  再有就是

sum += (x-i+)*(y-j+);

  这个算法我没看懂,不知道是否正确。

重构:

  其实原来代码已经改得差不多了,只剩下少许小错和瑕疵。我在这里只说一下我的算法:

  我的算法是,穷举出两个点(P1,P2)的所有组合情况,只要P1可以是某个矩形的左上角,P2可以是某个矩形的右下角(P1_X<P2_X,P1_Y<P2_Y),则构成了一个矩形。

 /*
 矩形的个数
 在一个3*2的矩形中,可以找到6个1*1的矩形,4个2*1的矩形3个1*2的矩形,
 2个2*2的矩形,2个3*1的矩形和1个3*2的矩形,总共18个矩形。
 给出A,B,计算可以从中找到多少个矩形。 

 输入:
 本题有多组输入数据(<10000),你必须处理到EOF为止
 输入2个整数A,B(1<=A,B<=1000) 

 输出:
 输出找到的矩形数。 

 样例:

 输入:
 1 2
 3 2 

 输出:
 3
 18

 作者:薛非
 出处:http://www.cnblogs.com/pmer/   “C语言初学者代码中的常见错误与瑕疵”系列博文 

 */

 #include <stdio.h>

 int count( int , int ); 

 int main( void )
 {
   int A , B ;

   while ( printf( "输入2个整数A,B(1<=A,B<=1000)" ),
           scanf( "%d%d" , &A , &B )!= EOF
         )
   {
      printf( "%d\n" , count( A , B ) );
   }

   ;
 }

 int count( int A , int B )
 {
    int x1 , y1 ;//第一个点的坐标
    int x2 , y2 ;//第二个点的坐标
     ;

     ; x1 <= B ; x1 ++ )
        ; y1 <= A ; y1 ++ )//穷举第一个点的各种可能
           ; x2 <= B ; x2 ++ )
              ; y2 <= A ; y2 ++ )//穷举第二个点的各种可能
             {
                if ( x1 < x2 && y1 < y2 )
                   num ++ ;
             }

    return num ;
 }

BUG

  这个代码的不足之处在于没有认真思考答案是否在int类型的表示范围之内。在 飞鸟_Asuka 网友提出是否“时间复杂度比较大”的问题后,我一并考虑了这两个问题。结论是:1.这个问题用数学的办法很容易解决,不过采用这种方案对学习编程是不利的,因为求解太容易了;2.答案确实有可能超过int类型的表示范围(假如int最大能表示到231-1的话)。这应该算是重构代码中存在的一个BUG。我将在以后的博文中给出修正及数学解答。

  在此感谢飞鸟_Asuka 网友的提醒。

C语言初学者代码中的常见错误与瑕疵(7)的更多相关文章

  1. C语言初学者代码中的常见错误与瑕疵(23)

    见:C语言初学者代码中的常见错误与瑕疵(23)

  2. 一个超复杂的间接递归——C语言初学者代码中的常见错误与瑕疵(6)

    问题: 问题出处见 C语言初学者代码中的常见错误与瑕疵(5) . 在该文的最后,曾提到完成的代码还有进一步改进的余地.本文完成了这个改进.所以本文讨论的并不是初学者代码中的常见错误与瑕疵,而是对我自己 ...

  3. C语言初学者代码中的常见错误与瑕疵(5)

    问题: 素数 在世博园某信息通信馆中,游客可利用手机等终端参与互动小游戏,与虚拟人物Kr. Kong 进行猜数比赛. 当屏幕出现一个整数X时,若你能比Kr. Kong更快的发出最接近它的素数答案,你将 ...

  4. C语言初学者代码中的常见错误与瑕疵(19)

    见:C语言初学者代码中的常见错误与瑕疵(19)

  5. C语言初学者代码中的常见错误与瑕疵(14)

    见:C语言初学者代码中的常见错误与瑕疵(14) 相关链接:http://www.anycodex.com/blog/?p=87

  6. 分数的加减法——C语言初学者代码中的常见错误与瑕疵(12)

    前文链接:分数的加减法——C语言初学者代码中的常见错误与瑕疵(11) 重构 题目的修正 我抛弃了原题中“其中a, b, c, d是一个0-9的整数”这样的前提条件,因为这种限制毫无必要.只假设a, b ...

  7. C语言初学者代码中的常见错误与瑕疵(9)

    题目 字母的个数 现在给你一个由小写字母组成字符串,要你找出字符串中出现次数最多的字母,如果出现次数最多字母有多个那么输出最小的那个. 输入:第一行输入一个正整数T(0<T<25) 随后T ...

  8. 要心中有“数”——C语言初学者代码中的常见错误与瑕疵(8)

    在 C语言初学者代码中的常见错误与瑕疵(7) 中,我给出的重构代码中存在BUG.这个BUG是在飞鸟_Asuka网友指出“是不是时间复杂度比较大”,并说他“第一眼看到我就想把它当成一个数学问题来做”之后 ...

  9. C语言初学者代码中的常见错误与瑕疵(1)

    曾在豆瓣上看到过一个小朋友贴出他自己的代码(http://www.douban.com/group/topic/40293109/),当时随口指点了几句.难得这位小朋友虚心修正.从善如流,不断地改,又 ...

随机推荐

  1. iOS交互WebService(cxf框架)

    公司后台java用的cxf框架,说是iOS.Android.web客户端都可以通用,但是我还是第一次遇到,所以做的时候遇到了不小的坑.下面总结下我开发中遇到的问题以及解决方案: 首先,后台提供了一份接 ...

  2. spring data mongodb 配置遇到的几个问题

    一. mongodb 2.2版本以上的配置 spring.data.mongodb.uri = mongodb://newlook:newlook@192.168.0.109:27017/admin ...

  3. uri和url的简单理解

    URL:统一资源定位符 也就是网址 例如 http://www.microsoft.com/ URI:通用资源标志符 http://www.acme.com/support/suppliers.htm

  4. Mysql数据库设置定时任务

    最近手头在做一个拍卖的电商项目. 中间需要将到点的拍卖会状态设置为进行中. 我们的解决方案是Mysql的定时器任务,这里进行一个简单的总结. 1.使用范围 不是所有的MySQL版本都支持,Mysql ...

  5. objective c,copy, mutableCopy区别

    copy总是返回不能被修改的对象,mutableCopy返回可以被修改的对象 例: NSArray *array = @[@"test", @"test2"]; ...

  6. 【安装操作系统】VMware 中安装 Redhat 5

    引言 已有一台 Windows XP 家用机,安装 Linux 虚拟机,一不小心就会走弯路,因此本文提供一些入门级的经验来帮助你躲开歧途. 欢迎来到 lovickie 的博客 http://www.c ...

  7. Scala主构造器、私有构造器、构造器重载

    Scala中的主构造器跟在定义类的时候声明类名之后 如下: class scala(arg : String) { // } private[this] 修饰该字段只能被当前所对应的对象所访问,其他对 ...

  8. html5移动开发--js温馨提示

    1.a标签执行js笔试 <a id="myID" href="javascript:myfuction();"></a> 2.实时监听i ...

  9. 64位sql server 如何使用链接服务器连接Access

    原文:64位sql server 如何使用链接服务器连接Access 测试环境 操作系统版本:Windows Server 2008 r2 64位 数据库版本:Sql Server 2005 64位 ...

  10. QTP DataTable全攻略(1)

    上一篇 / 下一篇  2009-07-27 00:14:16 / 个人分类:qtp 查看( 575 ) / 评论( 0 ) / 评分( 0 / 0 ) 下面的代码可能有点乱,基本涉及到常用的datat ...