ACM实习报告

这是我当年实习的实习报告,写的不算好,当时数据结构没学好,不会用链表这些东西。

第一部分:基础问题

1.2

1.实验题目

17世纪法国数学家加斯帕在《数学的游戏问题》中讲的一个故事:n个教徒和n个非教徒在深海上遇险,必须将一半的人投入海中,其余的人才能幸免于难,于是想了个办法:2n个人围成一个圆圈,从第一个人开始依次循环报数,每数到第九个人就将他扔入大海,如此循环直到仅剩n个人为止 。问怎样的排法,才能使每次投入大海的都是非教徒。

2.需求分析

本演示程序用VC编写,完成从文件中输入任意的整数n,并把排好序的字符串输出到一个文件中。

①   输入的形式和输入值的范围:输入文件由一行构成,就是n的值。其中n是整数。

②   输出的形式:输出文件中是一行字符串,字符串由n个‘@’字符(代表教徒)和n个‘+’ 字符(代表非教徒)排列构成。该排列使得按照前面的约定每次投入大海的都是非教徒。  

③   程序所能达到的功能:完成从文件中输入任意的整数n,并把排好序的字符串输出到 一个文件中。该排列使得按照前面的约定每次投入大海的都是非教徒。  

④   测试数据:

输入文件中n=15,输出文件为@@@@+++++@@+@@@+@++@@+++@++@@+

3.概要设计

  1)为了实现上述程序功能,需要定义一个数组:

2)本程序包含1个函数:

主函数main()

4.详细设计

实现概要设计中定义的所有数据类型,对每个操作只需要写出伪码算法。

1) 数组类型

#define N 100

int A[N] ;

2)  主函数的主要操作伪码算法

首先从文件中读取n,然后在数组中赋值2*n个64(‘@’的ASCLL值为64)

for(z=0;z<m;z++)

     A[z]=64;

然后对数组从头到尾遍历,除了‘+’每到第九个就赋值为34(‘+’的ASCLL值为34),直到赋了n个‘+’为止。

最后把数组中的值一一输出到文件中。

fp=fopen("b.txt","w");

  for(z=0;z<m;z++)

   fprintf(fp,"%c ",A[z]);

   fclose(fp);

5.调试分析

在运行中主要遇到逻辑错误一步步的通过调试找出来。

6.使用说明

程序名为1.2.exe,运行环境为Windows。

在输入文件a.txt中存储一个整型n值。

程序执行完后会自动生成b.txt文件中有排好序的字符串。

7.测试结果

8.附录

源代码如下:

#include<stdio.h>

#define N 100

int main()

{

   int i=1,j,z,v=0,g=1; //g表示需要投进海的非教徒,通过i来遍历到第九个人投海。

   int n,m;         //n表示教徒或者非教徒的人数,m来表示教徒和非教徒总数

   FILE *fp;

   fp=fopen("a.txt","r");  //打开一个a.txt文件用于只读

   if(fp==NULL) return -1;

   while(!feof(fp))

   {

   fscanf(fp,"%d",&n);     //在文件中读取n的值

   }

   m=2*n;    

   fclose(fp);   //读取完后关闭文件

   int A[N];

   for(z=0;z<m;z++)  //对一个m大小的数组赋初值'@'

    A[z]=64;

   while(g<=n)      //非教徒还没全部投海则继续,否则停止

   {

   for(j=v;j<=m-1&&i<=8;) //通过i来遍历到第九个人投海

   {

   if(A[j]==43)     //如果A[j]=='+'时,j++

   {

   if(j==m-1)    //如果A[j]=='+'&&j=m-1时,j=0从头开始遍历

      j=-1;

   j++;

   }

    elseif(j==m-1) //如果A[j]!='+'&&j==m-1,则j=0从头开始

   {

    i++;j=0;

    }

    else   //如果A[j]!='+'&&j!=m-1,则i++,j++

   {

    i++;j++;

   }

   }

   //当i到第九个时

   if(i==9&&A[j]!=43) //当i到第九个且这个数是'@'

   {

   A[j]=43;      //对其赋值'+'

   if(j==m)

       v=0;

   else

    v=j+1;

   i=1;

   g++;

   }

   else if(i==9&&A[j]==43)  //当i到第九个且这个数是'+'

   {

    while(A[j+1]==43&&j<=28) //则一直往下查找是'@'时对其赋值

   {

    j++;

   if(j==m)j=0;

    }

   A[++j]=43;

   if(j==m)

     v=0;

   else

    v=j+1;

   i=1;

   g++;

   }

   }

   fp=fopen("b.txt","w"); //执行完后创建一个只写文件b.txt

   for(z=0;z<m;z++)

    fprintf(fp,"%c ",A[z]); //把数组中的字符串输出到文件b.txt中

   fclose(fp);      //执行完后关闭文件

   return 0;

   }

 

1.3

1.实验题目

我们要求找出具有下列性质数的个数(包含输入的自然数n)。先输入一个自然数n(n<=1000),然后对此自然数按照如下方法进行处理: 1.不作任何处理; 2.在它的左边加上一个自然数,但该自然数不能超过原数最高位数字的一半; 3. 加上数后,继续按此规则进行处理,直到不能再加自然数为止。

2.需求分析

本演示程序用VC编写,完成题目要求输入一个自然数n,然后输出满足三个条件的数的个数。

输入的形式和输入值的范围:自然数n,并使n<=1000。

输出的形式:整数。

程序所能达到的功能:输出满足条件的数的个数。

测试数据:输入6

输出6

3.概要分析

1)为了实现上述程序功能,需要用一个while循环找出最高位数字和一个switch语句来进行求满足条件的数的个数:

2)本程序包含1个函数:

主函数main()

4.详细设计

实现概要设计中定义的所有数据类型,对每个操作只需要写出伪码算法。

1)定义一个整型数N存放输入数据;

2)找出整型数N的最高位数字n

n=N;

while(n/10!=0)

{ n=n/10;}

3)当n=1时,求得满足条件的数有1;

当n=2时,求得满足条件的数有2,12;

当n=3时,求得满足条件的数有3,13;

当n=4时,求得满足条件的数有4,14,24,124;

当n=5时,求得满足条件的数有5,15,25,125;

……

所以有如下switch语句来求满足条件的个数

switch(n/2)

 {

 case 0:num+=0;break;

 case 1:num+=1;break;

 case 2:num+=3;break;

 case 3:num+=5;break;

 case 4:num+=9;break;

 }

 printf("%d\n",num+1);

5.调试分析

在调试过程中发现最高位2和3是同样的个数,所以后来在switch中把switch(n)改为了switch(n/2),大大简化的程序。

6.使用说明

程序名为1.3.exe,运行环境为Windows。程序执行后显示

请输入一个不大于1000的整数:

然后在光标出输入一个不大于1000且不以0开头(除了0)的数字,再按回车将会显示执行后的结果。

7.测试结果

8.附录

源代码如下:

#include<stdio.h>

int main()

{

 int N,n,num=0;        //N代表输入的值,num统计满足条件的个数并赋初值0

 printf("请输入一个不大于1000的整数N\n");

 scanf("%d",&N);

 n=N;

 while(n/10!=0)        //找出最高位的数字

 { n=n/10;}

 switch(n/2)       //通过最高位的数字一半来分类处理

 {

 case 0:num+=0;break;

 case 1:num+=1;break;

 case 2:num+=3;break;

 case 3:num+=5;break;

 case 4:num+=9;break;

 }

 printf("%d\n",num+1); //输出满足条件的个数

 return 0;

}

1.5

1.实验题目

蛇形矩阵是由1开始的自然数依次排列成的一个矩阵上三角形。

2.需求分析

要求打印出一个不大于100阶的矩阵上三角形,且打印的数字由1开始的自然数。

(1) 输入的形式和输入值的范围:本题有多组数据,每组数据由一个正整数N组成。(N不大于100)

(2) 输出的形式:对于每一组数据,输出一个N行的蛇形矩阵。两组输出之间不要额外的空行。矩阵三角中同一行的数字用一个空格分开。行尾不要多余的空格。 

(3) 程序所能达到的功能:完成一个蛇形矩阵的输出。

(4) 测试数据:输入5

                 输出 1 3 6 10 15

2 5 914

4 8 13

7 12

11

 

3.概要设计

为了实现上述程序功能,需要定义一个二维数组:

a[100][100];

本程序包含1个函数:

主函数main();

4.详细设计

实现概要设计中定义的所有数据类型,对每个操作给出伪码算法。对主程序写出伪码算法。

1)定义一个整型二维数组存放蛇形矩阵中的值

a[100][100];

2)通过while来控制多组数据输入

while(scanf("%d",&N))

3)由蛇形矩阵的规律从左下角往右上角的遍历有如下算法

s=1;                

a[0][0]=s;

for(k=1;k<=N-1;k++)

for(i=k,j=0;i>=0,j<=k;i--,j++)  //通过i--,j++来实现这个规律

{

    a[i][j]=s+1;

    s++;

        }

4)给N阶蛇形矩阵输完值后再输出蛇形矩阵

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

{

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

           {

           if(j<g-1)

              printf("%d ",a[i][j]);

           else

              printf("%d",a[i][j]);

           }

        printf("\n");         

         g--;

}

5.调试分析

一开始没有找出这个遍历顺序导致输出结果并不是要求的,后来进过深入的对问题的分析,再转化为简洁的一个二重循环就能遍历出蛇形矩阵。

6.使用说明

程序名为1.5.exe,运行环境为Windows。程序执行后显示

输入一个N,再回车将会输出一个N阶的蛇形矩阵。

再接着还可以输入N,直到输入0为止。

7.测试结果

8.附录

源代码如下:

#include<stdio.h>

intmain()

{

 int s,N,i,j,k,a[100][100],g;         //s用来存放自然数,定义了一个二维数组

 while(scanf("%d",&N))          //控制多组数据测试,直到输入0为止

 {

     if(N==0) return 0;             //如果输入值为0,则终止程序

     else

     {

       s=1;                 //对自然数赋初值1

        a[0][0]=s;

       for(k=1;k<=N-1;k++) //通过二重循环来给蛇形矩阵随着s的增加来赋值

       for(i=k,j=0;i>=0,j<=k;i--,j++)  //通过k控制没次行的开始行数,i--,j++来//使从左下角到右上角的遍历;

           {

           a[i][j]=s+1;

           s++;

           }

 

        g=N;

        for(i=0;i<N;i++)    //通过二重循环来输出蛇形矩阵

       {

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

           {

           if(j<g-1)

              printf("%d ",a[i][j]);

           else

              printf("%d",a[i][j]);

           }

        printf("\n");          //没输出一行后换行

         g--;

       }

     }

 }

 return 0;

}

 

 

1.6

1.实验题目

输出7 和7 的倍数,还有包含7 的数字例如(17,27,37,...,70,71,72,73,...)

2.需求分析

要求输入一个整数N(N不大于30000),要求输出从小到大排列的不大于N的与7有关的数字,每行一个。

(1) 输入的形式和输入值的范围:输入一个整数N(N不大于30000);

(2) 输出的形式:输出从小到大排列的不大于N的与7有关的数字,每行一个;

(3) 程序所能达到的功能:输出所有与7有关的数字;

(4) 测试数据:

            输入20

              输出7

              14

              17

            

 

3.概要设计

为了实现上述程序功能,需要设计一个for循环还遍历寻找与7有关的数字。

本程序包含1个函数:

主函数main();

4.详细设计

实现概要设计中定义的所有数据类型,对每个操作给出伪码算法。

1)     定义一个整数N,通过键盘输入N

2)     通过for循环依次找与7有关的数字

for(i=1;i<=N;i++)    //从1到N排列的不大于N的与7有关的数字,每行一个。

 {

  if(i%7==0)        //i是否是7的倍数

   printf("%d\n",i);

  else if(i%10==7)     //i是否个位上含有7

   printf("%d\n",i);

  else if(i/10%10==7) //i是否十位上含有7

   printf("%d\n",i);

  else if(i/100%10==7)//i是否百位上含有7

   printf("%d\n",i);

  else if(i/1000%10==7) //i是否千位上含有7

   printf("%d\n",i);

 }

5.调试分析

在设计程序时有时个、十、百、千位数字描述的不正确,导致程序终止或得到错误结果。

6.使用说明

程序名为1.6.exe,运行环境为Windows。程序执行后显示

请输入一个整数N,使N小于等于3000

输入一个满足条件的N,按回车,将会在屏幕上显示1到N之间的与7有关的数字。

7.测试结果

8.附录

源代码如下:

#include<stdio.h>

intmain()

{

 int N,i;

 printf("请输入一个整数N,使N小于等于3000\n");

 scanf("%d",&N);

 for(i=1;i<=N;i++)    //从1到N排列的不大于N的与7有关的数字,每行一个。

 {

  if(i%7==0)        //i是否是7的倍数

   printf("%d\n",i);

  else if(i%10==7)     //i是否个位上含有7

   printf("%d\n",i);

  else if(i/10%10==7) //i是否十位上含有7

   printf("%d\n",i);

  else if(i/100%10==7)//i是否百位上含有7

   printf("%d\n",i);

  else if(i/1000%10==7) //i是否千位上含有7

   printf("%d\n",i);

 }

 return 0;

}

1.7

1.实验题目

第四平方和定理,又称为拉格朗日定理:每个正整数都可以表示为至多4个正整数的平方和。如果把0包括进去,就正好可以表示为4个数的平方和。比如:5 = 0^2 + 0^2 + 1^2 + 2^2 ,7 = 1^2 + 1^2 + 1^2 + 2^2 (^符号表示乘方的意思)对于一个给定的正整数,可能存在多种平方和的表示法。要求你对4个数排序: 0 <= a <= b <= c<= d 并对所有的可能表示法按 a,b,c,d 为联合主键升序排列,最后输出第一个表示法

2.需求分析

求第四平方和定理,要求输入一个正整数N (N<5000000),是N=a*a+b*b+c*c+d*d,对a,b,c,d排序,依次输出从小到大的四位数。

(1) 输入的形式和输入值的范围:输入整数N (N<5000000)

(2) 输出的形式:4个非负整数,按从小到大排序,中间用空格分开;

(3) 程序所能达到的功能:求第四平方定理;

(4) 测试数据:输入5

         输出0 0 1 2

         输入773535

         输出1 1 267 838

3.概要设计

本程序需要设计一个四重循环来依次查找满足条件的第一组数。

本程序包含1个函数:

主函数main()

4.详细设计

实现概要设计中定义的所有的数据类型,对每个操作给出伪码算法。

1)    定义一个整数N;定义a,b,c,d分别代表四个数的平方和;

2)    为了查找一组从小到大排列的数使用四重循环

for(a=0;a*a<N;a++)

{

for(b=a;b*b<N&&b>=a;b++)

{

for(c=b;c*c<N&&c>=b;c++)

{

  for(d=c;d*d<N&&d>=c;d++)

  {

     if(a*a+b*b+c*c+d*d==N)

        {  printf("%d%d %d %d\n",a,b,c,d); return 0; }

   }

  }

}

}  

5.调试分析

一开始我的程序为

for(a=0;a<5000000;a++)

 {

  for(b=a;b<5000000&&b>=a;b++)

  {

   for(c=b;c<5000000&&c>=b;c++)

   {

    for(d=c;d<5000000&&d>=c;d++)

    {

    

      if(a*a+b*b+c*c+d*d==N)

     {printf("%d %d %d%d\n",a,b,c,d); return 0;}

    }

   }

  }

 }

由于这样a,b,c,d遍历的次数非常之大,也没有并要,时间复杂度太大了,后来改了条件才使773535这个数的四个非负整数输出来。

6.使用说明

程序名为1.7.exe,运行环境为Windows。程序执行后显示

请输入一个小于5000000的整数N

输入一个满足条件的整数N,回车

将会在屏幕上显示想要的结果。

7.测试结果

8.附录

源代码如下:

#include<stdio.h>

int main()

{

int N,a,b,c,d;

 printf("请输入一个小于5000000的整数N\n");

 scanf("%d",&N);

 for(a=0;a*a<N;a++)

 {

  for(b=a;b*b<N&&b>=a;b++)

  {

   for(c=b;c*c<N&&c>=b;c++)

   {

    for(d=c;d*d<N&&d>=c;d++)

    {

    

      if(a*a+b*b+c*c+d*d==N)

         {printf("%d %d %d%d\n",a,b,c,d); return 0;}   //输出一组则退出程序运行

    }

   }

  }

 }  

return 0;

}

1.8

1.实验题目

有一长度为N(1<=N<=10)的地板,给定两种不同瓷砖:一种长度为1,另一种长度为2,数目不限。要将这个长度为N的地板铺满,一共有多少种不同的铺法?

例如,长度为4的地面一共有如下5种铺法:

4=1+1+1+1

4=2+1+1

4=1+2+1

4=1+1+2

4=2+2

编程用递归的方法求解上述问题。

2.需求分析

本演示程序用VC 编写,完成对一个长度为N的地面各种铺瓷砖的方法的总数

(1) 输入的形式和输入值的范围:输入整数N (1<=N<=10)

 (2) 输出的形式:输出一个数,代表所有不同的瓷砖铺放方法的总数;

 (3) 程序所能达到的功能:求长度为N的地板瓷砖的铺法总数;

(4) 测试数据:输入4

             输出5

3.概要设计

1)为了实现上述程序功能,需要定义一个整数N代表地板长度

2)本程序包含2个函数:

1.主函数main()

2.递归函数求方法总数f()

各函数间关系如下:

main——>f

4.详细设计

实现概要设计中定义的所有数据类型,对每个操作给出伪码算法。

1)地板长度N

2)函数int f(int n)

{

 if(n>=3) returnf(n-1)+f(n-2);

         else return n;

}

3)函数调用并输出结果

printf("%d\n",f(N));

5.调试分析

当n=1或2时,方法总数就是n。

而且他们满足f(n)=f(n-1)+f(n-2);

所以可以用递归来描述这个程序更为简洁。

5.调试分析

对于n等于1或2时方法就为n。

6.使用说明

程序名为1.8.exe,运行环境为Windows。程序执行后显示

请输入大于等于1小于等于10的一个地板长度整数N:

输入一个N,回车

屏幕上将会显示满足条件的方法数。

7.测试结果

8.附录

源代码如下:

#include<stdio.h>

intf(int n)

{

 if(n>=3) return f(n-1)+f(n-2); //斐波那契数列递归

 else return n;      //当n<=2时,返回n

}

intmain()

{

 int N;

 printf("请输入大于等于1小于等于10的一个地板长度整数N:");

 scanf("%d",&N);

 printf("%d\n",f(N));

 return 0;

}

 

 

第二部分:经典算法

一、 分治法

1.实验题目

编写自然归并合并排序算法:对于初始给定的数组,通常存在多个长度大于1的已自然排好序的子数组段.例如,若数组a中元素为{4,8,3,7,1,5,6,2},则自然排好序的子数组段有{4,8},{3,7},{1,5,6},{2}.用一次对数组a的线性扫描就足以找出所有这些排好序的子数组段,然后将相邻的排好序的子数组段两两合并,构成更大的排好序的子数组段({3,4,7,8},{1,2,5,6}).继续合并相邻排好序的子数组段,直至整个数组已排好序

2.需求分析

本演示程序用VC 编写,完成自然归并合并排序算法。

(1)输入的形式和输入值的范围:输入一个大小为n的整型自然数数组;

(2) 输出的形式:输出从小大排列的自然数;

(3) 程序所能达到的功能:实现对自然有序的数据排序;

(4) 测试数据:输入4,8,3,7,1,5,6,2

           输出1,2,3,4,5,6,7,8

3.概要设计

1)为了实现上述程序功能,需要定义一个两个整型数组,分别存放输入数据和每一自然有序的小段开始在数组中的下标值,还要定义一个整型数m存放有多少段自然有序的小段。

2)本程序包含6个函数:

主函数main()

对两段相邻的片段排序函数Merge ()

输出数组函数Print ()

线性扫描函数f ()

两两合并相邻函数MergePass(()

合并排序函数MergeSort ()

  各函数间关系如下:

                              Merge

                         

                              Print

 

main                          f

 

                                  MergePass

                                 

                                  MergeSort

4.详细设计

实现概要设计中定义的所有的数据类型,对每个操作给出伪码算法。对主程序和其他模块也都需要写出伪码算法。

1) 数组类型

int m; 

int t[N];

2) 自然合并排序算法的基本操作

为了程序的操作,把t数组和m变量定义为全局变量。

void Merge(int c[],int d[],int left,int middle,intright) 

{

 inti=left,j=middle+1,k=right;

 while((i<=middle)&&(j<=right))

 {

  if(c[i]<=c[j])

  d[left++]=c[i++];

  else

  d[left++]=c[j++];

 }

 if(i>middle)     

  for(intq=j;q<=right;q++) 

 d[left++]=c[q];

 else

  for(intp=i;p<=middle;p++)     

   d[left++]=c[p];

}

 

void Print(int a[],int n)  

{

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

 cout<<a[i]<<" ";

 cout<<endl;

}

 

void f(int a[],int b[],int n,int &m)

{

 int j=0;

 b[j++]=0;

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

 {

  if(a[i+1]<a[i])

   b[j++]=i+1;

 }

 m=j;

 Print(b,j);

}

 

void MergePass(int x[],int y[],int s,int n)

{

 int i=0;    

 while(i<=m-2*s)  

 {

  intr=((i+2*s)<m)?t[i+2*s]:n; 

 Merge(x,y,t[i],t[i+s]-1,r-1);

  i=i+2*s;

 }

 if(i+s<m)      

  Merge(x,y,t[i],t[i+s]-1,n-1);

 else

  if(i<m)    

  {

   for(intj=t[i];j<=n-1;j++)

    y[j]=x[j];

  }

}

 

void MergeSort(int a[],int n)  

{

 int *b=new int[n];

 int s=1;

 while(s<m)  

 {

 MergePass(a,b,s,n);  

  s+=s;

 MergePass(b,a,s,n);  

  s+=s;

 }

 delete[] b;   

}

3) 其他模块伪码算法

int main()

{

 int n,a[N],i;

 printf("请输入要排序的个数:");

 scanf("%d",&n);

 printf("请输入%d个自然数:",n);

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

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

 Print(a,n);

 f(a,t,n,m);

 MergeSort(a,n);

 Print(a,n);

 return 0;

}

 

5.调试分析

通过对每一个小模块调试测试成功后,再对整个代码调试测试,直到正确为止。

6.使用说明

程序名为自然合并排序算法.exe,运行环境为Windows,程序执行后显示:

请输入要排序的个数:

输入n,回车。

请输入n个自然数:

输入n个自然数,回车。

屏幕上将会在第一行输出排序前的数组,第二行输出各个小片段开始的数组下标值,第三行输出排序后的数组。

7.测试结果

8.附录

源代码如下:

#include<iostream>

using namespace std;

#define N 100

int m;      //自然合并排序中线性扫描中自然有序的段数,已初始化为0

int t[N];  //全部初始化为0

void Merge(int c[],intd[],int left,int middle,int right)  //合并c[left:middle]和c[middle+1:right]到d[left:right]

{

 int i=left,j=middle+1,k=right;

 while((i<=middle)&&(j<=right))

 {

  if(c[i]<=c[j])

   d[left++]=c[i++];

  else

   d[left++]=c[j++];

 }

 if(i>middle)     

  for(int q=j;q<=right;q++)  //i>middle说明i已经复制到d中了,所以要把剩下的j复制到b中,并且此时c中元素是有序的,所以可以直接复制

   d[left++]=c[q];

 else

  for(int p=i;p<=middle;p++)     

   d[left++]=c[p];

}

void Print(int a[],intn)   //输出数组函数

{

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

  cout<<a[i]<<" ";

 cout<<endl;

}

void f(int a[],int b[],intn,int &m) //线性扫描自然有序的的数组,b数组记录每一小段的数组开始下标值,并把b赋给了t

{

 int j=0;

 b[j++]=0;

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

 {

  if(a[i+1]<a[i])

   b[j++]=i+1;

 }

 m=j;

 Print(b,j);//m表示有多少段自然有序的数组

}

void MergePass(int x[],inty[],int s,int n)

{

 int i=0;    //i表示子数组段下标值,每次加2*s完成相邻两段的合并排序

 while(i<=m-2*s)   //判断是否还剩两个子数组段

 {

  int r=((i+2*s)<m)?t[i+2*s]:n;  //当自然排好序片段为偶数时,就r=n,表示刚好两两合并成功,最后没有多余的子数组段

  Merge(x,y,t[i],t[i+s]-1,r-1);

  i=i+2*s;

 }

 if(i+s<m)       //当还剩大于三个奇数个最小片段时执行

  Merge(x,y,t[i],t[i+s]-1,n-1);

 else

  if(i<m)    //i<m表示有多余的子数组段,则直接复制在y[]后,因为该子数组已经排好序了

  {

   for(int j=t[i];j<=n-1;j++)

    y[j]=x[j];

  }

}

void MergeSort(int a[],intn)   //合并排序算法

{

 int *b=new int[n];//动态分配一个b[n]数组

 int s=1;

 while(s<m)    //有大于1个小自然数组段才执行

 {

  MergePass(a,b,s,n);   //合并到数组b

  s+=s;

  MergePass(b,a,s,n);   //合并到数组a,无论m为到少终将排序好的赋在a数组

  s+=s;

 }

 delete[] b;   //排好序后释放b[n]

}

int main()

{

 int n,a[N],i;

 printf("请输入要排序的个数:");

 scanf("%d",&n);

 printf("请输入%d个自然数:",n);

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

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

 Print(a,n);

 f(a,t,n,m);

 MergeSort(a,n);

 Print(a,n);

 return 0;

}

第三部分:北大oj

1003:

1. 实验题目

Howfar can you make a stack of cards overhang a table? If you have one card, youcan create a maximum overhang of half a card length. (We're assuming that thecards must be perpendicular to the table.) With two cards you can make the topcard overhang the bottom one by half a card length, and the bottom one overhangthe table by a third of a card length, for a total maximum overhang of 1/2 + 1/3 = 5/6 cardlengths. In general you can make n cards overhang by 1/2 + 1/3 + 1/4 + ... + 1/(n + 1) cardlengths, where the top card overhangs the second by 1/2, the second overhangstha third by 1/3, the third overhangs the fourth by 1/4, etc., and the bottomcard overhangs the table by 1/(n + 1). Thisis illustrated in the figure below.

翻译:你能在一张桌子上堆叠一堆卡吗?如果您有一张卡片,您可以创建半张卡片长度的最大悬垂。(我们假设卡片必须垂直于桌子。)用两张卡片可以使顶部卡片伸出底部一张卡片长度的一半,底部卡片悬挂在卡片长度的三分之一处,对于1/2 + 1/3 = 5/6卡片长度的总最大悬垂。一般来说,你可以使n卡悬垂1/2 + 1/3 + 1/4 + ... + 1 /+1)卡片长度,顶部卡片悬出1/2,第二张悬出1/3,第三悬出1/4等等,底部卡片悬挂在桌面上1 / (+ 1)。

2. 需求分析

本演示程序用VC编写,完成对卡片的叠放。

(1)输入的形式和输入值的范围:输入包含一个或多个测试用例,后面跟着一个包含数字0.00的行,表示输入结束。每个测试用例都是一个包含正浮点数c的单行,其值至少为0.01,最大为5.20; c将包含三位数字。

(2)输出的形式:对于每个测试案例,输出达到至少c卡片长度所需的最小数量的卡片。使用示例中显示的确切输出格式。

(3)程序所能达到的功能:完成对卡片的叠放。

(4)测试数据:

样例输入:1.00

3.71

0.04

5.19

0.00

样例输出:3 card(s)
61 card(s)
1 card(s)
273 card(s)

3. 概要设计

1)为了实现上述程序功能,需要定义一个float型的c:

float c=0.0;

2)本程序包含两个函数:

1主函数main()

2实现求最少卡片函数f()

4. 详细设计

实现概要设计中定义的所有的数据类型,对每个操作给出伪码算法。

int f(float c,int *n)

{

 floatadd=0.0;

 

 while(add<c)

 {

 add+=(float)1.0/(*n+1);

  (*n)++;

 }

 return(*n);

}

主函数:

int main()

{

 floatc=0.0;

 int n;

 while(scanf("%f",&c)){

 if(c==0.00) return 0;

 n=1;

 printf("%dcard(s)\n",f(c,&n)-1);

 }

 return 0;

}

5. 调试分析

因为此题要求数值为小数形式,所以在有的计算过程中需要我们强制转换为float型,例如add+=(float)1.0/(*n+1);

6. 使用说明

程序名为1003.exe,运行环境为Windows。程序执行后

从键盘输入一个数c,回车

将会在屏幕上显示结果。

7. 测试结果

8. 附录

源代码如下:

#include<stdio.h>

int f(float c,int *n)

{

 float add=0.0;

 while(add<c)

 {

  add+=(float)1.0/(*n+1);

  (*n)++;

 }

 return (*n);

}

int main()

{

 float c=0.0;

 int n;

 while(scanf("%f",&c)){

 if(c==0.00) return 0;

 n=1;

 printf("%dcard(s)\n",f(c,&n)-1);

 }

 return 0;

}

1004

1. 实验题目

Larry graduated this yearand finally has a job. He's making a lot of money, but somehow never seems tohave enough. Larry has decided that he needs to grab hold of his financialportfolio and solve his financing problems. The first step is to figure outwhat's been going on with his money. Larry has his bank account statements andwants to see how much money he has. Help Larry by writing a program to take hisclosing balance from each of the past twelve months and calculate his averageaccount balance.

翻译:拉里今年毕业,终于找到了工作。他赚了很多钱,但似乎从来没有足够的。拉里决定,他需要抓住他的财务组合,解决他的融资​​问题。第一步是弄清楚他的钱到底是怎么回事。拉里有他的银行账户报表,想看看他有多少钱。通过编写程序帮助拉里从过去12个月的每个月结算余额,并计算他的平均账户余额。

2. 需求分析

本演示程序用VC编写,完成对拉里平均账户余额的计算。

(1)输入的形式和输入值的范围:输入将是十二行。每一行将包含他在某个月份的银行账户期末余额。每个数字将是正面的,并显示给便士。不包括美元符号。

(2)输出的形式:产出将是一个单一的数字,即十二个月期末余额的平均值(平均值)。它将四舍五入到最接近的一分钱,之后立即以美元符号,然后是行尾。输出中将不会有其他空格或字符。

(3)程序所能达到的功能:按要求计算平均值。

(4)测试数据:

样例输入100.00 
489.12 
12454.12 
1234.10 
823.05 
109.20 
5.27 
1542.25 
839.18 
83.99 
1295.01 
1.75
样例输出$1581.42
3. 概要设计
1)为了实现上述程序功能,需要定义一个float型的数组,和一个变量
2)本程序包含1个函数:
主函数main()
4. 详细设计
实现概要设计中定义的所有数据类型,对每个操作给出伪码算法。
float a[12],average;
  float add=0;
  int i;
  for(i=0;i<12;i++){
         scanf("%f",&a[i]);
         add+=a[i];
  }
  average=add/12;
  printf("%c%.2lf\n",'$',average);
5.调试分析
因为此题精度问题定义double不准确,因此采用float型。
6.使用说明
程序名为1004.exe,运行环境为Windows。程序执行后
每行输入一个数据,输入十二个
则将会输出保留两位小数的计算结果。
7.测试结果
 
 
8.附录
源代码如下:
#include<stdio.h>
int main()
{
  float a[12],average;
  float add=0;
  int i;
  for(i=0;i<12;i++){
         scanf("%f",&a[i]);
         add+=a[i];
  }
  average=add/12;
  printf("%c%.2lf\n",'$',average);
  return 0;
}
 
1207
1. 实验题目

Problems in Computer Science are often classified as belonging to acertain class of problems (e.g., NP, Unsolvable, Recursive). In this problemyou will be analyzing a property of an algorithm whose classification is notknown for all possible inputs. 
Consider the following algorithm: 
1.       input n

2.       printn

3.       ifn = 1 then STO

4.       ifn is odd then   n <-- 3n+1

5.       else   n <-- n/2

6.       GOTO2

Given the input 22, the following sequence of numbers will beprinted 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1 

It is conjectured that the algorithm above will terminate (when a 1 is printed)for any integral input value. Despite the simplicity of the algorithm, it isunknown whether this conjecture is true. It has been verified, however, for allintegers n such that 0 < n < 1,000,000 (and, in fact, for many morenumbers than this.) 

Given an input n, it is possible to determine the number of numbers printedbefore the 1 is printed. For a given n this is called the cycle-length of n. Inthe example above, the cycle length of 22 is 16. 

For any two numbers i and j you are to determine the maximum cycle length overall numbers between i and j. 

翻译:计算机科学中的问题通常被归类为某类问题(如NP,Unsolvable,Recursive)。在这个问题中,您将分析一个算法的属性,该算法的分类对于所有可能的输入是未知的。 
考虑以下算法: 

1.输入n

   2.打印n

   3.如果n = 1,则停止

   4.如果n是奇数,则n <-3n + 1

   5.否则n < -  n / 2

   6.转到2

给定输入22,将打印下列数字序列22 11 3417 52 26 13 40 20 10 5 16 8 4 2 1 

推测上述算法将终止(当打印1时)任何积分输入值。尽管这个算法很简单,但是这个猜想是否真实是未知的。然而,已经证实,对于所有整数n使得0 <n <1000000(事实上,对于比这更多的数字) 

给定输入n,可以确定在1之前打印的数字的数量被打印。对于给定的n,这被称为n的周期长度。在上面的例子中,22的周期长度是16. 

对于任何两个数字i和j,您将确定i和j之间的所有数字的最大周期长度。 

2. 需求分析
本演示程序用VC编写,完成对一个区间的整数求最大循环长度。
(1)输入的形式和输入值范围:输入将由一系列的整数i和j,每行一对整数组成。所有整数将小于10,000,大于0. 

您应该处理所有的整数对,并确定每个整数对之间的所有整数(包括i和j)的最大循环长度。
(2)输出形式:对于每对输入整数i和j,您应该输出i,j,以及包含i和j之间的整数的最大循环长度。这三个数字应该由至少一个空格分隔,其中一行的全部三个数字以及每行输入的一行输出。整数i和j必须以输出中出现的顺序出现在输出中,并且应该跟随最大循环长度(在同一行上)。
(3)程序所能达到的功能:完成一个区间的最大循环长度的求取。
(4)测试数据:样例输入
1 10
100 200
201 210
900 1000
样例输出
1 10 20
100 200 125
201 210 89
900 1000 174
3. 概要设计
1)     为了实现上述程序功能,需要定义三个整型变量,两个用来存放输入的值,还有一个用来记录最大循环长度。
2)     本程序包含4个函数:
主函数main()
求最大长度函数f()
求最小值函数min()
求最大值函数max()
各函数间关系如下:
                      f
 
 
main                 min
 
                              max
4.详细设计
实现概要设计中定义的所有的数据类型,对每个操作给出伪码算法。
unsigned f(int n)
{
  int sum=0;
  while(n!=1)
  {
         if(n%2==1)
                 n=3*n+1;
         else
                 n=n/2;
         sum++;
  }
  return sum+1;
}
 
int min(int i,int j)
{
  int min;
  min=j;
  if(i<j)
         min=i;
         return min;    
}
 
int max(int i,int j)
{
  int max;
  max=i;
  if(j>i)
         max=j;
         return max;
}
 
int main()
{
  int i,j,k;
  while(scanf("%d%d", &i, &j) != EOF)
  {
         unsigned sum=0;
         for(k=min(i, j);k<=max(i,j);k++)
         {
                 sum=max(sum, f(k));
         }
         printf("%d %d %d\n",i,j,sum);
  }
  return 0;
}
5.调试分析
对于其中的输入已经是小的在前,大的在后,但是计算机就不知道,所以还要判断大小。
6.使用说明
程序名为1207.exe,运行环境为Windows。程序执行后 
输入测试数据回车就会得到结果。
7.测试结果
 
 
8.附录
源代码如下:
#include <stdio.h>
unsigned f(int n)
{
      int sum=0;
      while(n!=1)
      {
              if(n%2==1)
                      n=3*n+1;
              else
                      n=n/2;
              sum++;
      }
      return sum+1;
}
int min(int i,int j)
{
      int min;
      min=j;
      if(i<j)
              min=i;
              return min;    
}
int max(int i,int j)
{
      int max;
      max=i;
      if(j>i)
              max=j;
              return max;
}
 
int main()
{
      int i,j,k;
      while(scanf("%d%d", &i, &j) != EOF)
      {
              unsigned sum=0;
              for(k=min(i, j);k<=max(i,j);k++)
              {
                      sum=max(sum, f(k));
              }
              printf("%d %d %d\n",i,j,sum);
      }
      return 0;
}
1338
1.     实验题目
Ugly numbers are numbers whose only prime factors are 2, 3 or 5. The sequence 
1, 2, 3, 4, 5, 6, 8, 9, 10, 12, ... 
shows the first 10 ugly numbers. By convention, 1 is included. 
Given the integer n,write a program to find and print the n'th ugly number. 
翻译:丑陋的数字是唯一的主要因素是2,3或5的数字。序列 
1,2,3,4,5,6,8,9,10,12 ... 
显示前10个丑陋的数字。按照惯例,1包括在内。 
给定整数n,写一个程序来查找和打印第n个丑陋的数字。
2.需求分析
本演示程序用VC编写,完成对第n个丑数的输出。
1输入的形式和输入值范围:输入的每一行都包含一个后缀整数n(n <= 1500)。输入由n = 0的行终止。
2输出的形式:对于每一行,输出第n个丑陋的数字:不要处理n = 0的行。
3程序所能达到的功能:完成对第n个丑数的输出。
4测试数据:
样例输入
1
2
9 
0
样例输出
1
2
10
3.概要设计
1)     为了实现上述程序功能,需要定义一个1500大小的整型数组存放丑数。
2)     本程序包含3个函数
主函数main()
求最小值函数min()
求丑数函数f()
4.详细设计
实现概要设计中定义的所有的数据类型,对每个操作给出伪码算法。
int Min(int a,int b,int c)
{
      int min=(a<b)?a:b;
      min=(min<c)?min:c;
      return min;
}
 
void f()
{
      int i=0;
      int *p2,*p3,*p5;
      A[i++]=1;
      p2=A;
      p3=A;
      p5=A;
      while(i<1500)
      {
              int min=Min(2*(*p2),3*(*p3),5*(*p5));
              A[i]=min;
              while(2*(*p2)<=A[i])
                      ++p2;
              while(3*(*p3)<=A[i])
                      ++p3;
              while(5*(*p5)<=A[i])
                      ++p5;
              ++i;
      }
}
 
int main()
{
      int n;
      f();
      while(scanf("%d",&n)!=EOF&&n>=1&&n<=1500)
      {
              printf("%d\n",A[n-1]);
      }
      return 0;
 
}
 
5. 调试分析
通过2,3,5对之前找出来的丑数相乘找更大的丑数这一思想非常好,通过指针也非常好操作。
6. 使用说明
程序名为1338.exe,运行环境为Windows。
程序执行后输入一个整数回车将会输出结果。
7. 测试结果
 
 
8. 附录
源代码如下:
#include<stdio.h>
#include<stdlib.h>
 
int A[1500];
 
int Min(int a,int b,int c)
{
      int min=(a<b)?a:b;
      min=(min<c)?min:c;
      return min;
}
 
void f()
{
      int i=0;
      int *p2,*p3,*p5;
      A[i++]=1;
      p2=A;
      p3=A;
      p5=A;
      while(i<1500)
      {
              int min=Min(2*(*p2),3*(*p3),5*(*p5));
              A[i]=min;
              while(2*(*p2)<=A[i])
                      ++p2;
              while(3*(*p3)<=A[i])
                      ++p3;
              while(5*(*p5)<=A[i])
                      ++p5;
              ++i;
      }
}
 
int main()
{
      int n;
      f();
      while(scanf("%d",&n)!=EOF&&n>=1&&n<=1500)
      {
              printf("%d\n",A[n-1]);
      }
      return 0;
 
}
 
2301
1. 实验题目
Superbowl Sunday is nearly here. In order to pass the time waiting for the half-time commercials and wardrobe malfunctions, the local hackers have organized a betting pool on the game. Members place their bets on the sum of the two final scores, or on the absolute difference between the two scores. 
Given the winning numbers for each type of bet, can you deduce the final scores? 
翻译:超级碗星期天差不多在这里。为了打发等待半天广告和衣柜故障的时间,当地的黑客组织了游戏池。会员们把注意力放在两个最终分数的总和上,或者是两个分数的绝对差值。 
鉴于每种类型的赌注中奖号码,你能推断最后的分数? 
2. 需求分析
本演示程序用VC编写,完成对一组分值的预测。
(1)输入的形式和输入值的范围:输入的第一行包含n,即测试用例的数量。每行代表一个测试用例。每个测试案例给出s和d,非负整数表示两个最终得分之间的总和和(绝对)差异。

(2)输出的形式:对于每个测试用例,输出一个给出最后两个分数的线,最大的是第一个。如果没有这样的分数,输出一个包含“不可能”的行。回想一下,足球比分总是非负整数。

(3)程序所能达到的功能:完成对一组分值的预测。

(4)测试结果:

样例输入

2

40   20

20   40

样例输出

30   10

impossible

3. 概要设计

1)    为了实现上述程序功能,需要定义三个整型变量用于存储输入的值。

int T,A,B;

2)    本程序包含1个函数

主函数main()

4. 详细设计

实现概要设计中定义的所有的数据类型,对每个操作给出伪码算法。

scanf("%d",&T);

   while(T--)

    {

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

       if(A<B) printf("impossible\n");

       else if((A+B)%2!=0) printf("impossible\n");

       else

       {

           a=(A+B)/2;

           b=(A-B)/2;

           if(a<b){int c=a;a=b;b=c;}

           printf("%d %d\n",a,b);

       }   

}

通过这部分语句来进行程序功能的实现。

5. 调试分析

对于输出来要通过比较大小来从大到小的输出。

6. 使用说明

程序名为2301.exe,运行环境为Windows。程序执行后

输入T表示输入测试的数据组数,然后依次输入每组回车将会得到结果。

7. 测试结果

8. 附录

源代码如下:

#include<stdio.h>

int main()

{

    intT,A,B;

    inta,b;

   scanf("%d",&T);

   while(T--)

    {

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

       if(A<B) printf("impossible\n");

       else if((A+B)%2!=0) printf("impossible\n");

       else

       {

           a=(A+B)/2;

           b=(A-B)/2;

           if(a<b){int c=a;a=b;b=c;}

           printf("%d %d\n",a,b);

       }   

    }

   return 0;   

}   

 写的不怎么好,大家参考参考就好了。

猜你喜欢

转载自blog.csdn.net/qq_41045071/article/details/80965038