ACM实习报告书

版权声明:@ly https://blog.csdn.net/lytwy123/article/details/82872916

目录

第一部分:基础题目

1.2………………………………………02

1.3………………………………………11

1.5………………………………………15

1.6………………………………………18

1.7………………………………………20

1.8………………………………………24

 

第二部分:算法题目

回溯法 …………………………………27

 

第三部分:北大oj

1003 ……………………………………32

1004 ……………………………………36

1027 ……………………………………38

1338 ……………………………………46

 

 

第一部分 基础题目

1.2

1.实验题目

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

2.需求分析   

本演示程序用VC编写,用循环链表实现丢到海里的都是非教徒

  •  输入的形式和输入值的范围:输入文件由一行构成,就是n的值

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


③ 程序所能达到的功能:丢到海里的都是非教徒
④ 测试数据:

【输入范例】  15  

【输出范例】  @@@@+++++@@+@@@+@++@@+++@++@@+

 

3.概要设计

1)为了实现上述程序功能,需要定义单链表的抽象数据类型:
ADT LinkList {
数据对象:D={ai|ai∈IntegerSet,i=0,1,2,…,n,n≥0}
数据关系:R={<ai,ai+1>|ai,ai+1 ∈D}
2)本程序包含2个函数:
① 主函数main()
② 简单的排序函数,使筛选出的非教徒完全有序

4.详细设计

实现概要设计中定义的所有的数据类型,对每个操作给出伪码算法。对主程序和其他模块也都需要写出伪码算法。
1) 结点类型和指针类型
typedef struct node {
int sign;
struct Node *next;
}Node,*LinkListl;

2) 简单插入排序函数,排出非教徒顺序

void insertsort(Node *L1, Node *p)   //*L1是头结点,*p是指向当前位置的节点 

    Node *after, *front;  //*after代表之后传进来的异教徒序号,*front代表之前传进来的异教徒序号

 

    if (L1->next==NULL) 

    { 

        L1->next=p; 

        p->next=NULL; 

    } 

    else 

    { 

        front=L1; 

        after=L1->next; 

        while(1) 

        { 

            if (p->sign<after->sign) 

            { 

                p->next=front->next; 

                front->next=p; 

                return; 

            } 

 

            if(after->next==NULL) 

                break; 

            after=after->next; 

            front=front->next; 

        } 

        after->next=p; 

        p->next=NULL; 

    } 

}

5.调试分析
首先我们需要把所有教徒用循环链表构成一个环,再者通过给出的条件每数到第九个人就丢到海里说明是非教徒,所以我们要把丢出去非教徒存到另一个链表,然后将链表里的非教徒按照顺序来输出,最后在将循环链表遍历,把2教徒插到空的位置,调试将非教徒排序好的排序函数,还要用到文件,先将输入的n读到文件中再将排列输出到文件中。

6.使用说明

程序名为1.2教徒求生.exe,运行环境为windows。程序执行后显示

7.测试结果

1) 下运行程序,按下任意键,打开.cpp的文件所在的位置,会多出教徒输入.txt与教徒输出.txt两个文本文件,在教徒输入中输入n的值再运行程序,再打开教徒输出文件,就会显示出排列顺序

8. 附录

#include <stdio.h> 

#include <stdlib.h> 

//表示教徒标号的节点结构体类型 

typedef struct Node      

    int sign;    //教徒标号 

    struct Node* next; 

}Node,*LinkList; 

//简单的插入排序函数,使筛选出的异教徒完全有序 

void in(Node *L1, Node *p)   //*L1是头结点,*p是指向当前位置的节点 

    Node *after, *front;  //*after代表之后传进来的异教徒序号,*front代表之前传进来的异教徒序号

 

    if (L1->next==NULL) 

    { 

        L1->next=p; 

        p->next=NULL; 

    }  

    else 

    { 

        front=L1; 

        after=L1->next; 

        while(1) 

        { 

            if (p->sign<after->sign) 

            { 

                p->next=front->next;                                                                                                                                                                                 

                front->next=p; 

                return; 

            } 

 

            if(after->next==NULL) 

                break; 

            after=after->next; 

            front=front->next; 

        } 

        after->next=p; 

        p->next=NULL; 

    } 

}    //利用链表进行插入排序的函数,使筛选出来的异教徒标号严格有序 

//主函数 

FILE *fp1,*fp2;

 

void main() 

    int n;

    //scanf("%d",&n);

    

    fp1=fopen("教徒输入.txt","r");

    fp2=fopen("教徒输出.txt","w");

       if ((fp1==NULL)||(fp2==NULL))

       {      puts("不能打开文件!");     

           return ;  

       }

         fscanf(fp1,"%d",&n);

//  fprintf(fp1,"%d",n);

   

//  printf("%d",n);

    //  fclose(fp1);

   

//  fclose(fp2);

    int count, Nodenumber;   //计数变量和教徒总数 

    Node *p, *L, *rear;//*p是只想当前位置的动态指针,*L是指向头结点的指针,*rear是指向尾节点的指针 

    Node *L1;  //异教徒排序链表的头指针

 

    L=(Node *) malloc(sizeof(Node)); 

    L->next=NULL; 

    rear=L; 

 

    L1=(Node *) malloc(sizeof(Node)); 

    L1->next=NULL; 

  //建立教徒节点,输入标号,创建循环链表,将各教徒连成环

    for(count=1;count<=2*n;count++) 

    { 

        p=(Node*)malloc(sizeof(Node)); 

        p->sign=count; 

        rear->next=p; 

        rear=p; 

        if (count==2*n) 

            p->next=L; 

    } 

    Nodenumber=2*n;   //初始化教徒数目 

    rear=L; 

    p=L->next; 

//开始逐个筛选异教徒,直到只剩N个

    while(Nodenumber>n)    

    { 

        for (count=1; count<=9; count++)  //从1至9依次计数 

        { 

            if (p==L) 

            { 

                p=p->next;   //遇到头结点继续向后递进,但count--使其保持不变,从而不把头节点计算在内 

               rear=rear->next; 

                count--; 

                continue; 

            } 

 

            if(count!=9)   //还未数到第九个,继续向后递进 

            { 

                p=p->next; 

                rear=rear->next; 

            } 

        } 

 

        rear->next=p->next;  //一个异教徒找出,p指向该异教徒节点,将该节点从循环链表中取出 

        in(L1, p);  //对取出的节点执行插入排序,将其有序放入由筛选出的异教徒组成的链表 

        p=rear->next;  //p指向原取出节点的后一节点,为下一轮计数做准备 

        Nodenumber--;   //教徒数相应减一 

    } 

  rear=L1;

    for(p=L1->next;p!=NULL;rear=rear->next, p=p->next)   //根据存放筛选出的异教徒的链表输出各教徒的排列方式 

    {  

        if (rear==L1) 

        { 

            for(count=1; count<p->sign; count++)

           //  printf("@");

       //  printf("+");

                fprintf(fp2,"@"); 

            fprintf(fp2,"+"); 

        } 

        else 

        { 

            for(count=rear->sign+1; count<p->sign; count++)

           //  printf("@");

       //  printf("+");

                fprintf(fp2,"@");

            fprintf(fp2,"+"); 

        } 

    } 

    if (rear->sign!=2*n) 

    { 

        for(count=rear->sign+1; count<=2*n; count++) 

           //printf("@");

           fprintf(fp2,"@"); 

    } 

    fprintf(fp2,"\n");

    printf("\n");

1.3

1.实验题目

我们要求找出具有下列性质数的个数(包含输入的自然数n)。先输入一个自然数n(n<=1000),然后对此自然数按照如下方法进行处理: 1.不作任何处理;  2.在它的左边加上一个自然

数,但该自然数不能超过原数最高位数字的一半; 3. 加上数后,继续按此规则进行处理,直到不能再加自然数为止. 

2.需求分析

本演示程序用VC编写,完成题目基本要求。

① 输入的形式和输入值的范围:第一行一个数t,表示有t组数据 之后每组数据占一行,每行一个数n 
② 输出的形式:每组数据占一行,一个数,表示满足条件的数的个数

③ 程序所能达到的功能:通过输入输出完成题目的要求

④ 测试数据:
A. 输入测试组数1

B. 输入需要测试的数6

C. 输出满足条件的个数

3.概要设计

1)为了实现上述程序功能,需要使用函数调用方式。

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

① 主函数main()
②判断个位数的函数f1()

③ 判断十位数的函数f10()
④ 判断百位数的函数f100()

4.详细设计

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

定义三个int型自定义函数

int f1(int num)//判断输入个位数满足条件的数

{

    if(num/2==0)

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

   else if(num/2==1)

   {num=(num/2)+1;

   printf("%d\n",num);}

       else if(num/2==2)

    {num=(num/2)+2;

    printf("%d\n",num);}

    else if(num/2==3)

    {num=(num/2)+3;

    printf("%d\n",num);}

       else if(num/2==4)

       {num=(num/2)+6;

       printf("%d\n",num);}

       return 0;

}

int f10(int num)//通过判断十位数满足的条件得数

{

    int n10;

    n10=num/10;

    f1(n10);

    return n10;

}

int f100(int num)//通过判断百位数满足条件的个数

{

    int n100;

    n100=num/100;

f1(n100);

return n100;

}

主函数中函数的调用

void main()

{

    int i,t,num;

    printf("请输入t组测试数据组数t:");

    scanf("%d",&t);

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

    {

       scanf("%d",&num);

       if((num>=0)&&(num<10))

       {

           f1(num);

       }

       else if((num>=10)&&(num<100))

       {

           f10(num);

       }

        else if((num>=100)&&(num<1000))

       {

           f100(num);

       }

    }

}

5.调试分析

a.调试中运行程序难免会出现一些语法错误,使得编译器不能能通过编译,所以有思想后应该先解决语法错误,再来看逻辑错误,通过一步步改进算法将逻辑错误排查,这样还不能使得你得到最终的结果,你需要使用多组测试,而不仅仅是一组输入输出来完成你的程序。

6.使用说明

程序名为满足三个条件的数字的个数.cpp,运行环境为windows。程序执行后显示

7.测试结果

1) 输入t组测试的t事先进行多组测试的第一步

1 2 3

2) 输入需要测试的数据

6 110 250,

输出结果

6 1 2

8.附录

#include<stdio.h>

int f1(int num)

{

    if(num/2==0)

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

   else if(num/2==1)

   {num=(num/2)+1;

   printf("%d\n",num);}

    else if(num/2==2)

    {num=(num/2)+2;

    printf("%d\n",num);}

    else if(num/2==3)

    {num=(num/2)+3;

    printf("%d\n",num);}

       else if(num/2==4)

       {num=(num/2)+6;

       printf("%d\n",num);}

       return 0;

}

int f10(int num)

{

    int n10;

    n10=num/10;

    f1(n10);

    return n10;

}

int f100(int num)

{

    int n100;

    n100=num/100;

    f1(n100);

    return n100;

}

void main()

{

    int i,t,num;

    printf("请输入t组测试数据组数t:");

    scanf("%d",&t);

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

    {

       scanf("%d",&num);

       if((num>=0)&&(num<10))

       {

           f1(num);

       }

       else if((num>=10)&&(num<100))

       {

           f10(num);

       }

       else if((num>=100)&&(num<1000))

       {

           f100(num);

      }

   }

}

1.5

1.实验题目

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

2.需求分析

本演示程序用VC编写,完成输入的数据按照蛇形矩阵要求输出。

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

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

③ 程序所能达到的功能:完成蛇形矩阵的生成

④ 测试数据:
A.输入测试的最大长度

 B. 依次按照蛇形矩阵的要求输出,输出呈蛇形矩阵

1 3 6 10 15 2 5 9 14 4 8 13 7 12 11

3.概要设计

1)为了实现上述程序功能,需要定义二维数组

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

① 主函数main()

4.详细设计

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

  1. 定义一个二维数组最大长度为100,num[100][100]
  2. 主函数代码如下

int main()

{

    int num[100][100]={0},i,j,N;//   i代表行数,j代表列数

    printf("请输入蛇形矩阵的行数:");

    scanf("%d",&N);    从行来看

    int k=1;                给数组赋值即num[0][0]=1

    for(i=0;i<N;i++)       // 循环遍历二维数组元素

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

       {

          num[i-j][j]=k++;   //给矩阵输出赋值,斜着输出

       }  

       for(i=0;i<N;i++)      //遍历输出上三角即蛇形矩阵

       {printf("\n");

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

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

       return 0;

}

5.调试分析

通过初步调试,始终不能将蛇形矩阵打印出来,首先我们需要定义一个二维数组,然后将它遍历,但是蛇形矩阵要求是输出上三角而其排列必须是斜线输出。所以算法一定要满足输出条件,

6.使用说明

程序名为蛇形矩阵.cpp,运行环境为windows。程序执行后显示

按任意键退出测试框

7.测试结果

1) 输出蛇形矩阵排列

8附录

#include<stdio.h>

int main()

{

    int num[100][100]={0},i,j,N;

    printf("请输入蛇形矩阵的行数:");

    scanf("%d",&N);

    int k=1;

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

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

       {

          num[i-j][j]=k++;

       }  

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

       {printf("\n");

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

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

       return 0;

}

1.6

1.实验题目

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

2.需求分析

本演示程序用VC编写,查找7和7的倍数以及包含7的数字

  •  输入的形式和输入值的范围:一个整数N。(N 不大于30000)
  •  输出的形式:从小到大排列的不大于N 的与7 有关的数字,每行一个。
    测试数据:
    A. 输入一个数字20

B.输出7 14 17
3.概要设计

1)为了实现上述程序功能,需要定义一些变量做循环以及判断。

2)本程序包含1个函数

① 主函数main()

4.详细设计

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

主函数:

int main()

{

    int N,i,j;

    printf("输入一个整数N:");

    scanf("%d",&N);

    if((N>=0)&&(N<=30000))    //N的范围

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

       {

           if(i%7==0)          //判断7的倍数以及7

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

       else

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

           {

              if(j%10==7)          //判断含7的数

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

              else

                  if((j/10==7)||(j/100==7)||(j/1000==7)||(j/10000==7)||((j/10)%10==7))        //判断十位数,百位数,千位数位数上含7的数

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

              break;

           }

       }

           else

              printf("数据溢出");

           return 0;

}

5.调试分析

题目要求需要找到7的倍数,含7的数字以及7本身,输出7的倍数与7十分简单,但是输出含7的数字因为百位千位所以稍加难度,此题只要掌握求位数的方法,以及遍历出到所输入数字全部含7以及倍数的数字即可。

6.使用说明

程序名为输出7和7的倍数还有包含7的数字.cpp,运行环境为windows。程序执行后显示

按任意键退出程序运行框

7.测试结果

⑴输入需要测试到的数据。

⑵输出1到要测试数据中7和7的倍数以及包含7的数。

8.附录

#include<stdio.h>

//int fun

int main()

{

    int N,i,j;

    printf("输入一个整数N:");

    scanf("%d",&N);

    if((N>=0)&&(N<=30000))

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

       {

           if(i%7==0)

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

       else

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

           {

              if(j%10==7)

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

              else

                  if((j/10==7)||(j/100==7)||(j/1000==7)||(j/10000==7)||((j/10)%10==7))

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

              break;

           }

       }

           else

              printf("数据溢出");

           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.需求分析

本演示程序用VC编写,输入一个数,找出它由4个数的平方和所相加,输出这些数按照升序排列

  •  输入的形式和输入值的范围:一个正整数N (N<5000000)
  •  输出的形式:4个非负整数,按从小到大排序,中间用空格分开
  •  程序所能达到的功能:找到一个数是由哪4个数的平方和相加而得
  •  测试数据:
    A. 输入一个5或者773535

B. 输出0 0 1 2

1 1 267 838

3.概要设计

1)为了实现上述程序功能,用到四重循环以及判断条件
2)本程序包含1个函数:
① 主函数main()

4.详细设计

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

Main()函数

int main()

{

    int N;

    printf("请输入一个正整数N:");

    while(scanf("%d",&N)!=EOF)

    {

       int a,b,c,d;

       for(a=0;a*a<N;a++)  //判断a的值,给a累加

           break;     //只输出一次循环的值

           for(b=a;b*b<N;b++) //判断b的值,给b累加

              for(c=b;c*c<N;c++)//判断c的值,给c累加

                  for(d=c;d*d<N;d++)//判断d的值,给d累加

                  {

                     if((a*a+b*b+c*c+d*d==N)&&(a<=b)&&(b<=c)&&(c<=d))//判断结果成立的条件

                     {

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

                     }

                  }

    }

return 0;


 

5.调试分析
我们需要输入一个数字,求出这个数字由其他四个数字的数的平方和所加而成,而4个数大小依次为0 <= a <= b <= c <= d,我们尅利用循环将所有可能的数字遍历出来,但是结果只需要你输出第一个表示法,那么就需要循环一次即可。

6.使用说明

程序名为第四平方和定理又称拉格朗日定理。cpp,运行环境为windows。程序执行后显示

7.测试结果

1) 一重循环判断a得值,二重循环判断b的值,三重循环判断c得值,四重循环判断d得值最后判断条件需要满足

0 <= a <= b <= c <= d

a*a+b*b+c*c+d*d==N

8.附录

#include<stdio.h>

#include<stdlib.h>

int main()

{

    int N;

    printf("请输入一个正整数N:");

    while(scanf("%d",&N)!=EOF)

    {

       int a,b,c,d;

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

           break;

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

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

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

                  {

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

                     {

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

                     }

                  }

                  break;

    }

return 0;

}

1.8

1.实验题目

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

2.需求分析

本演示程序用VC编写,求出输入铺瓷砖的长度一共有多少种方法
① 输入的形式和输入值的范围:

只有一个数N,代表地板的长度
② 输出的形式:输出一个数,代表所有不同的瓷砖铺放方法的总数
③ 程序所能达到的功能:得到铺指定长度瓷砖的方法

④ 测试数据:
A.
长度为4的地面一共有如下5种铺法:

4=1+1+1+1

4=2+1+1

4=1+2+1

4=1+1+2

4=2+2

输入4

得到5种方法

3.概要设计

2)本程序包含1个函数:
① 主函数main()
② 求铺瓷砖方法的函数f(),在此函数不断调用f(),递归调用。

4.详细设计

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

/*f(1)=1 1=1

f(2)=2 2=2 1+1=2

f(3)=3 1+2 1+1+1 2+1

所以f(3)=f(1)+f(2)     

f(n)=f(n-2)+f(n-1)     斐波罗锲数列


int f(int n)          //自定义求铺瓷砖方法的函数

{    

    if(n==1||n==2)    //如果瓷砖长度为1或者2方法则为1和2

     return n;

    else

       if((n>2)&&(n<=10))   

     return (f(n-1)+f(n-2));   递归调用

       else

           if(n>10)

              return (-1);

}

int main()

{

    int N;

    printf("请输入地板的长度:");

    scanf("%d",&N);

    printf("%d\n",f(N));  //在输出语句中调用自定义函数f()

    return 0;

}

5.调试分析

可以发现如果铺长度为1的瓷砖只有一种方法1,铺长度为2的瓷砖有两种方法1+1,2,。铺长度为3的瓷砖有3种方法1+1+1,2+1,2+1. /*f(1)=1 1=1

f(2)=2 2=2 1+1=2

f(3)=3 1+2 1+1+1 2+1

所以f(3)=f(1)+f(2)      

f(n)=f(n-2)+f(n-1)     斐波罗锲数列

运用斐波罗锲数列的关系即找到关系

6.使用说明

程序名为瓷砖问题.cpp,运行环境为windows。程序执行后显示

7.测试结果

1)自定义函数f():
» 不断递归调用自身

2)主函数main()

在主函数中调用f()函数得到结果

8.示例

#include<stdio.h>

int f(int n)

{    

   if(n==1||n==2)

    return n;

   else

       if((n>2)&&(n<=10))

    return (f(n-1)+f(n-2));

       else

          if(n>10)

              return (-1);

}

int main()

{

   int N;

   printf("请输入地板的长度:");

   scanf("%d",&N);

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

   return 0;

}

第二部分 算法题目

1.实验题目

八皇后问题是一个古老而著名的问题,是回溯算法的典型例题。该问题是十九世纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。

2.需求分析

本演示程序用VC编写,完成对八皇后放置在同一棋盘的方法并把它们分别打印出来。

  •  输入的形式和输入值的范围:不要求输入

② 输出的形式:输出一共有多少种方法数,在文件中会遍历出各种情况。
③ 程序所能达到的功能:求出八皇后摆放在棋盘上的所有方法数

3.概要设计

1)为了实现上述程序功能,需要定义一个判断八皇后所在棋盘上可行的方法数的函数:queen8(int L)   //L代表行
2)本程序包含7个函数:
① 主函数main()
② 判断八皇后所在棋盘上可行的方法数queen8()

4.详细设计

实现概要设计中定义的所有的数据类型,对每个操作给出伪码算法。对主程序和其他模块也都需要写出伪码算法。
void queen8(int L)//遍历出每种排列     L代表行

 {   

    int x,y;      //棋盘的列和行

    if (8==L)     //判断是否放置八个皇后在棋盘上

    {      

        n++;      

        fprintf(fp,"%d\n",n);   

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

        {            

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

            {           

                fprintf(fp,"%d",queen[y][x]);               

                if(queen[y][x]==1)//判断该位置是否摆皇后棋子

                    fprintf(fp,"■");             

                else        

                    fprintf(fp,"□");          

            }           

            fprintf(fp,"\n\n");        

        }

        return;    

    }    

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

    {         //判断对于当前x列是否可以放棋子

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

        {           //列                         //右斜            //左斜               

            if((queen[y][x]||(x-(L-y)>=0)&&(queen[y][x-(L-y)])||(x+(L-y)<8)&&(queen[y][x+(L-y)])))//判断列右斜左斜是否可以插入皇后

                break;        

        }        

        if (y==L)

        {            

            queen[L][x]=1;  // x代表列          

            queen8(L+1);    //每次都在不同行放置棋子 ,因此不用进行行检查        

            queen[L][x]=0;    //回朔法,找不到合适的位置摆放皇后,回到上一行的摆放皇后棋子    

        }    

    }

}

5.调试分析
八皇后问题要求各个皇后不会同在一行一斜线一列上,定义一个二维数组表示8*8棋盘,先将棋盘初始化为0(0表示非皇后,1表示皇后),然后将数组第一个元素为皇后。通过判断一次一次找出各行的摆放皇后的位置,若某一行找不到摆放皇后的位置,将回溯到上一行重新找摆放皇后的位置,反复至此,直到棋盘上放置八个皇后,方法数加一。反复至此,找到所有能在棋盘上摆放的方法数。

6.使用说明

程序名为八皇后问题1.cpp,运行环境为windows。程序执行后显示

7.测试结果

测试结果正确。

8.附录

#include<stdio.h>

FILE *fp;

int queen[8][8]; //定义8*8棋盘为二维数组

int n; //可行的方法数

void queen8(int L)//遍历出每种排列    L代表行

 {   

    int x,y;      //棋盘的列和行

    if (8==L)     //判断是否放置八个皇后在棋盘上

    {      

       n++;      

       fprintf(fp,"%d\n",n);   

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

       {            

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

           {           

              fprintf(fp,"%d",queen[y][x]);               

              if(queen[y][x]==1)//判断该位置是否摆皇后棋子

                  fprintf(fp,"■");             

              else        

                  fprintf(fp,"□");          

            }           

           fprintf(fp,"\n\n");        

        }

       return;    

    }    

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

    {         //判断对于当前x列是否可以放棋子

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

       {          //列                         //右斜            //左斜               

           if((queen[y][x]||(x-(L-y)>=0)&&(queen[y][x-(L-y)])||(x+(L-y)<8)&&(queen[y][x+(L-y)])))//判断列右斜左斜是否可以插入皇后

              break;        

        }        

       if (y==L)

       {            

           queen[L][x]=1;  // x代表列          

           queen8(L+1);    //每次都在不同行放置棋子 ,因此不用进行行检查        

           queen[L][x]=0;    //回朔法,找不到合适的位置摆放皇后,回到上一行的摆放皇后棋子    

        }    

    }

}

int main()

{   

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

    int y,x;    

    for (y=0;y<8;y++) //给整个棋盘初始化,全部不摆皇后

    {        

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

       {            

           queen[y][x]=0;        

       }

    }   

    queen8(0);  

    fprintf(fp,"一共有%d种方法",n);

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

    return 0;

}

第三部分 北大oj

1003,1004,1207,1338

1003

  1. 实验题目

How far can you make a stack of cards overhang a table? If you have one card, you can create a maximum overhang of half a card length. (We're assuming that the cards must be perpendicular to the table.) With two cards you can make the top card overhang the bottom one by half a card length, and the bottom one overhang the table by a third of a card length, for a total maximum overhang of 1/2 + 1/3 = 5/6 card lengths. In general you can make n cards overhang by 1/2 + 1/3 + 1/4 + ... + 1/(n + 1) card lengths, where the top card overhangs the second by 1/2, the second overhangs tha third by 1/3, the third overhangs the fourth by 1/4, etc., and the bottom card overhangs the table by 1/(n + 1). This is 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编写,完成该程序所要实现的功能

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

② 输出的形式:对于每个测试案例,输出达到至少c卡片长度所需的最小数量的卡片。使用示例中显示的确切输出格式
③ 程序所能达到的功能:找出 指定数目的长度最少由多少卡片完成
④ 测试数据:

示例输入

1.00

3.71

0.04

5.19

0.00

示例输出

3张卡片

61张(s)

1张(s)

273卡(s)

 

3.概要设计

1)为了实现上述程序功能,需要定义一个累加卡片长度函数:
int f(double count)

2)本程序包含7个函数:
① 主函数main()
② 累加卡片长度函数int f()

4.详细设计

实现概要设计中定义的所有的数据类型,对每个操作给出伪码算法。对主程序和其他模块也都需要写出伪码算法。
1) 累加卡片长度函数
int f(double count)

{

    int i=2;

    int n=0;

    double sum;

    for(sum=0.0;sum<count;n++)

       sum=sum+(double)1/i++;

       if(sum>=count)

           return n;

}

5.调试分析
本题是将一张第一张卡片伸出桌子1/2,第二张伸出第一张卡片的1/3,以此类推,当所叠加的卡片长度超过用户输入的卡片长度,即返回用了几张卡片。

6.使用说明

程序名为北大oj1003.cpp,运行环境为windows。程序执行后显示
7.测试结果

输入一个浮点型数据,使用多组测试,输入0.00结束程序。

8.附录

#include<stdio.h>

int f(double count)

{

    int i=2;

    int n=0;

    double sum;

    for(sum=0.0;sum<count;n++)

       sum=sum+(double)1/i++;

       if(sum>=count)

           return n;

}

int main()

{

    double c;

    while(scanf("%lf",&c))

    {

       if(c==0.00)

           return 0;

       else

           printf("%d card(s)\n",f(c));

      

    }

    return 0;

}

1004

1.实验题目

Larry graduated this year and finally has a job. He's making a lot of money, but somehow never seems to have enough. Larry has decided that he needs to grab hold of his financial portfolio and solve his financing problems. The first step is to figure out what's been going on with his money. Larry has his bank account statements and wants to see how much money he has. Help Larry by writing a program to take his closing balance from each of the past twelve months and calculate his average account balance.

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

2.需求分析

本演示程序用VC编写,帮助拉里计算出他的平均账户余额

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

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

③ 程序所能达到的功能:求出12个月平均数
④ 测试数据:

示例输入

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个函数:
① 主函数main()

主函数里定义一个长度为12的数组,存入每个月的钱,在求出平均数。

4.详细设计

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

int main()

{

    double num[N];

       int i=0;

    double average;

    double sum=0.0;

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

       scanf("%lf",&num[i]);

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

       sum=sum+num[i];

     average=sum/N;

     printf("$");

     printf("%.2lf",average);

     printf("\n");

     return 0;

}  

5.调试分析
可以输入与测试例子不同的数字进去检验程序是否为偶然性,用户自己输入数据存入数组,在求出平均数。

6.使用说明

程序名为北大oj1004.cpp,运行环境为windows。程序执行后显示

7.测试结果

输入12组数据,输出平均数前带有$。

8.附录

#include<stdio.h>

#define N 12

int main()

{

    double num[N];

       int i=0;

    double average;

    double sum=0.0;

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

       scanf("%lf",&num[i]);

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

       sum=sum+num[i];

     average=sum/N;

     printf("$");

     printf("%.2lf",average);

     printf("\n");

     return 0;

}

1207

1.实验题目

Problems in Computer Science are often classified as belonging to a certain class of problems (e.g., NP, Unsolvable, Recursive). In this problem you will be analyzing a property of an algorithm whose classification is not known for all possible inputs. 
Consider the following algorithm: 
       1.input n
       2.print n
       3.if n = 1 then STOP
       4. if n is odd then  

n <-- 3n+1    
       5. else  

n <-- n/2
        6. GOTO 2

Given the input 22, the following sequence of numbers will be printed 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 is unknown whether this conjecture is true. It has been verified, however, for all integers n such that 0 < n < 1,000,000 (and, in fact, for many more numbers than this.) 
Given an input n, it is possible to determine the number of numbers printed before the 1 is printed. For a given n this is called the cycle-length of n. In the example above, the cycle length of 22 is 16. 

For any two numbers i and j you are to determine the maximum cycle length over all 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 34 17 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编写,

① 输入的形式和输入值的范围:输入将由一系列的整数i和j,每行一对整数组成。所有整数将小于10,000,大于0. 
您应该处理所有的整数对,并确定每个整数对之间的所有整数(包括i和j)的最大循环长度。

② 输出的形式:对于每对输入整数i和j,您应该输出i,j,以及包含i和j之间的整数的最大循环长度。这三个数字应该由至少一个空格分隔,其中一行的全部三个数字以及每行输入的一行输出。整数i和j必须以输出中出现的顺序出现在输出中,并且应该跟随最大循环长度(在同一行上)。
③ 程序所能达到的功能:完成指定区间内找到最大周期长度
④ 测试数据:

示例输入

1 10 
100 200 
201 210 
900 1000

示例输出

1 10 20 
100 200 125 
201 210 89 
900 1000 174

3.概要设计

1)本程序包含3个函数:
① 主函数main()
② 求一个数字最大的区间长度得值函数f()
③ 求两个数中的最小值函数min()
④ 求两个数中的最大值的函数max()

各函数间关系如下

                f
   main()       min()

              max()

4.详细设计

实现概要设计中定义的所有的数据类型,对每个操作给出伪码算法。对主程序和其他模块也都需要写出伪码算法。
int 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;//因为为1时也要打印

}

5.调试分析
让用户输入一个区间,通过上述公式计算出区间中数字的最大周期长度个数

6.使用说明

程序名为北大oj1207.cpp,运行环境为windows。程序执行后显示

7.测试结果

输入一个区间比如1 10,输出包含区间长度在内以及区间内数字的最大长度周期

8.附录

#include <stdio.h>

int 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;//因为为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)

    {

       int 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编写,完成将遍历1到1500的丑数

① 输入的形式和输入值的范围:输入的每一行都包含一个后缀整数n(n <= 1500)。输入由n = 0的行终止。
② 输出的形式:对于每一行,输出第n个丑陋的数字:不要处理n = 0的行

③ 程序所能达到的功能:找到1到1500里的丑数

④ 测试数据:
示例输入

1
2
9
0

示例输出

1
2
10

 

3.概要设计

1)本程序包含3个函数:
① 主函数main()
②判断三个数的大小,找出最小的数字Min()

③ 找出丑数并把它们存入数组中f()

各函数间关系如下:

                    f()

     main()          Min()
 

4.详细设计

实现概要设计中定义的所有的数据类型,对每个操作给出伪码算法。对主程序和其他模块也都需要写出伪码算法。
int Min(int a,int b,int c)//比较三个数的大小,找出最小的数

{

    int min=(a<b)?a:b;

    min=(min<c)?min:c;

    return min;

}

int f()     //遍历丑数

{

    int i=0;

    int *p2,*p3,*p5;

    A[i++]=1;

    p2=A;

    p3=A;

    p5=A;

    while(i<1500)

    {//找出丑数存入数组,不能整除2,3,5的数字不是丑数,不管他,将下一个数存入对应数组

       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;

    }

    return 0;

}

5.调试分析
丑数不能整除2,3,5.定义了三个指针,分别用来用与2,3,5相乘来遍历后面的丑数,如果遇到7,则将7不要,将8存入对应的位置,以此内推。

6.使用说明

程序名为北大oj1338.cpp,运行环境为windows。程序执行后显示

7.测试结果

输入一个数的序号,然后输出丑数,因为7不是丑数,所以序号9对应10。

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;

}

int f()     //遍历丑数

{

    int i=0;

    int *p2,*p3,*p5;

    A[i++]=1;

    p2=A;

    p3=A;

    p5=A;

    while(i<1500)

    {//找出丑数存入数组,不能整除2,3,5的数字不是丑数,不管他,将下一个数存入对应数组

       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;

    }

    return 0;

}

int main()

{

    int n;

    f();

    while(scanf("%d",&n)!=EOF&&n>=1&&n<=1500)//多组测试

    {

       printf("%d\n",A[n-1]);//因为数组下标比序号小一

    }

    return 0;   }

猜你喜欢

转载自blog.csdn.net/lytwy123/article/details/82872916