算法第一次作业

问题0:求几何图形的个数<?xml:namespace prefix = o ns = “urn:schemas-microsoft-com:office:office” />

问题描述

设有n*m个方格的棋盘(1<=m,n<=100),求出该棋盘中包含多少个正方形、多少个长方形(不包括正方形)。

  例如:当n=3m=2  

  正方形的个数有8个;即边长为1的正方形有6个;边长为2的正方形有2个。

  长方形的个数有10个;即2*1的长方形有4个;1*2的长方形有3个;3*1的长方形有2个;3*2的年长方形有1个。

  程序要求:输入nm,输出正方形的个数和长方形的个数。

例如: 输入:3 2      输出: 8  10

  运行示例:

  input n,m:1 1        output: 1 0

  input n,m:4 5         output:40 110

  input n,m:10 10        output:385 2640

  input n,m:30 20        output:4970 92680

  input n,m:50 50        output:42925 1582700

 

问题分析

我们可以把棋盘放到座标系中考虑。如图所示,为3*2的方格。在座标系中,每两点即可表示一个矩形。如(2,1(0,0)表示1*2的矩形。这里我们规定:用右上角的点A(x1,y1)和左下角的点B(x2,y2)来确定一个矩形,并且保证x2<x1,y2<y1.x1-x2=y1-y2A,B确定的是一个正方形,否则是一个领边不等的长方形。

<?xml:namespace prefix = v ns = “urn:schemas-microsoft-com:vml” />

 

数据结构

矩形的数据结构Rectangle=(P,R)

其中:P={0,1,2……n}   n=max(M,N)

      R={A,B}

      A={<x1,y1>|1<=x1<=M,1<=y1<=N}

      B={<x2,y2>|0<=x2<=x1,0<=y2<=y1 }

正方形的数据结构Square=(P,R)

其中P={0,1,2……n}   n=max(M,N)

      R={A,B}

      A={<x1,y1>|1<=x1<=M,1<=y1<=N}

      B={<x2,y2>|0<=x2<=x1,0<=y2<=y1,x1-x2=y1-y2 }

长方形(不包括正方形)的数据结构Oblong=P,R

其中P={0,1,2……n}   n=max(M,N)

      R={A,B}

      A={<x1,y1>|1<=x1<=M,1<=y1<=N}

      B={<x2,y2>|0<=x2<=x1,0<=y2<=y1,x1-x2<>y1-y2 }

 

上述数据结构中,P为从0MN的自然数集,RAB两点的关系。AB两点满足上面定义中的要求。

 

 

算法分析

正方形个数+长方形个数=所有矩形的个数。算出正方形和矩形的个数,即可得长方形的个数。我们先确定点A(x1,y1) 1<=x1<=M,1<=y1<=N然后再确定点B(x2,y2) 0<=x2<=x1,0<=y2<=y1 x1-x2=y1-y2时即为正方形。其流程图如下

 

C程序清单

main()

{

    int m,n;

    int i,j;

    int x,y;

    long int square=0,oblong=0;

 

    printf(“M,N=/n”);

    scanf(“%d %d”,&m,&n);

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

        for(j=1;j<=n;j++)

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

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

                    {

                        if((i-x)==(j-y))

                            square++;

                                          else oblong++;

                    }

    printf(“%6ld,%6ld”,square,oblong);

    getch();

 

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

问题一:求最大数

问题描述:

设有n个正整数(n<=20),将它们联成一排,组成一个最大的多位数。

  例如:n=3时,3个整数13312343联接成的最大整数为:34331213

  又如:n=4时,4个整数7134246联接成的最大整数为7424613

程序输入:n

 程序输出:n个数联接成的多位数。

 

问题分析:

此题猛一看很简单,其实不然。看第一遍时,偶以为就是把数按由大到小排列,然后合并。但给出的例子“n=4时,4个整数7134246联接成的最大整数为<?xml:namespace prefix = st1 ns = “urn:schemas-microsoft-com:office:smarttags” />7424613否定了偶的猜测。偶又以为是比较第一位数的大小,如果第一位数相同就比较第二位,以此类推。但自己给出的一组数“743421又否定鸟偶的猜测。要是按偶的算法,得出来的是742431,而正确结果应该是744231。所以此题的关键是,当一个数是另一个数的前半部分的情况。如果碰到这种情况,我们可以截去长数前面相同的部分然后再比较如果又相同又要截去又要比较如果又相同又要截去又要比较……所以这又是一个递归问题.

 

数据结构

 

算法分析

我们可以用字符串的形式存放数组,然后“比较”字符串的大小,把大的放在前面。其两个字符串s1s2具体的比较规则如下:

1.  先判断第一个字符,哪个大哪个就是“大数”。

2.  如果第一个字符相等,就判断第二个字符。以此类推。

3.  如果其中一个字符串所有的字符都比较完了还没分出大小(即其中一个字符串是另一个字符串的一部分),那么就把长的字符串截去前面相同的部分。然后把剩下的和原来短的那个字符串比较。

 

 

 

 

 

c程序清单

#include <string.h>

#include <stdio.h>

#include <conio.h>

 

#define min(x,y)    ((x)>(y)?(y):(x))

 

int NewStrcmp(char *pszNum1,char *pszNum2)

{

    unsigned int nMinLen;

    int nResult;

    if(strlen(pszNum1)==0)

        return -1;

    if(strlen(pszNum2)==0)

        return 1;

 

    nMinLen=min(strlen(pszNum1),strlen(pszNum2));

/*如果一个字符串是第二个字符串的前缀的话,则将长串与第一个字符串相同的部分*/

/*截去,将剩下的继续比较,当出现有字串长度为0的时候特殊处理*/

 

    if((nResult=strncmp(pszNum1,pszNum2,nMinLen))==0)

    {

        if(nMinLen==strlen(pszNum1))

        {

            return NewStrcmp(pszNum1,pszNum2+nMinLen);

        }

        else

        {

            return NewStrcmp(pszNum1+nMinLen,pszNum2);

        }

    }

    else

    {

        return nResult;

    }

 

}

 

main()

{

    unsigned int i,j,n;

    char *pszNum[20];

 

    printf(“/N(N<20):”);

    scanf(“%d”,&n);

 

    printf(“input %d number/n”,n);

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

    {

        pszNum[i]=calloc(5,sizeof(char *));

        gets(pszNum[i]);

    }

    putchar(‘/n’);

    /*用冒泡排序*/

    for(i=0;i<n+1;i++)

    {

        for(j=0;j<n-i;j++)

        {

            if(NewStrcmp(pszNum[j],pszNum[j+1])<0)

            {

                char *pTmp;

                pTmp=pszNum[j];

                pszNum[j]=pszNum[j+1];

                pszNum[j+1]=pTmp;

            }

        }

    }

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

        printf(“%s”,pszNum[i]);

    printf(“/n”);

    getch();

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

问题2:揹包问题

问题描述

设有一个揹包,可以放入的重量为S。现有N件物品,重量分别为W1,W2,…WNWi(1<=I<=N)均为正整数,从n件物品中挑选若干件,使得放入揹包的重量之和正好为S

测试数据:

 The number of object: 3 

 Total weight=7

 Weight of each object:9 6 2

 Output:

 Not find

 The number of object: 5

 Total weight=10

 Wweight of each object:1 6 2 7 5

 Output:

 Number: 1    Weight: 1

 Number: 3    Weight: 2

 Number: 4     Weight:7

 

问题分析

A1,A2……An为取出的满足条件的n件物品,即A1+A2+……+An=S.则有A1+A2+……A(n-1)=S-An. 也就是说,若揹包可放入的重量为S-An,N-1件物品中可取出n-1件物品A1,A2……A(n-1)满足要求。以此类推,必有当揹包可放入的重量为S-An+A(n-1)+……A2)时,从N-n+1件物品中可取出A1满足要求。分析得,此问题可用递归求解。

 

 

算法分析

可构造一递归函数Beibao(s,n)完成从n个数中取出若干个使其和等于s的任务。其中n个数存放在w[n]中。若w[n]能取出,则必有Beibao(s-w[n],n-a)有解;否则跳过w[n],计算Beibao(s,n-1);

 

 

 

 

 

 

c程序清单

#include<stdio.h>

 

 

int w[100];

main()

{

    int S,N;

    int i;

    printf(“beibao ke zhuang zhongliang:”);

    scanf(“%d”,&S);

    printf(“/n”);

    printf(“wupin geshu:”);

    scanf(“%d”,&N);

    printf(“/n”);

    printf(“input wupin zhongliang w[1]…w[N]:/n”);

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

        scanf(“%d”,&w[i]);

    if(Beibao(S,N))

        printf(“OK!/n”);

    else

        printf(“NO!/n”);

    getch();

}

 

int Beibao(int s,int n)

{

    if(s==0)      /*s0时,返回1 */

        return 1;

    if(s<0||(s>0&&n<1)) /* 当装入的物品重量大于s,或者物品装完还没装满时,*/

        return 0;       /*返回0,即无解*/

    if(Beibao(s-w[n],n-1))  /*当且仅当n-1个物品装入容量为s-w[n]的揹包有解时, */

    {                     /*可以装入w[n],并返回1 */

        printf(“%4d”,w[n]);

            return 1;

    }

    return Beibao(s,n-1);   /* 运行到这就说明n-1个物品装入容量为s-w[n]的揹包无解。*/

}                       /* 此时跳过w[n],计算把n-1个物品装入容量为s的情况*/

                       

点赞