C++入门十题

C++编程入门十题

 

1:数塔

2:数字排序问题

3:日历问题

4:约瑟夫问题

6:选美比赛

7:在霍格沃茨找零钱 

8:数圈

9:小A的计算器

10:找出直系亲属

 

 

1数塔 (ID: 1000 )

 

一、 问题描述

 

给定一个数塔,如下图所示。在此数塔中,从顶部出发,在每一节点可以选择走左下或右下,一直走到底层。请找出一条路径,使路径上的数值和最大。

     

                                 9         

                                  12   15       

                                10   6   8     

                              2   18   9   5   

                           19   7   10   4   16

 

二、 问题分析

  

这是一个求最大权值的问题,也就是说相当于问从顶层到底层的一个最大生成树的权值。我们可以从底层出发,每两个进行判断,将较大值传递到上面一层并标记,这样逐层传递,也就相当于把问题简化到先以最后一层为底层、倒数第二层为顶层,再以得到一次值传递的倒数第二层为底层、倒数第三层为为顶层······这样一直计算到顶层,则此时顶层已经得到了由下面所有层中的最大权值,此时顶层即为所求。而在计算中,我们也对路径进行了标记,在输出时,就只需输出得到最大权值的路径上若干个数值。

 

三、 算法分析

 

一个简单的求最优解的问题,使用传值的方式实现题目要求的权值计算,然后将对应最大权值的路径上的被标记的数值输出。

 

四、 详细设计(从算法到程序)

1. 主模块设计

a. 定义一个三维数组,分别用于逐层传值、标记、及输出最大权值上的值。

b.从最后一层开始,两两比较出较大值传递到上一层,并标记。

c. 传递到顶层是结果即是所求最大权值,输出。

d. 按照标记,逐步输出路径上的值。

e.根据上述设计,程序主体框架如下:

     

int main()

{

    int n;

    cin>>n;

    int A[n][n][3];      //定义数组

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

    for(int j=1;j<=i;j++)

    {

     cin>>A[i][j][1];

     A[i][j][2]=A[i][j][1];         //两个相同数组,一个用来运算一个用来输出

     A[i][j][3]=0;

}

    for(int i=n-1;i>=1;i--)

    for(int j=1;j<=i;j++)

    {

     if(A[i+1][j][1]>A[i+1][j+1][1])

     {

     A[i][j][1]=A[i][j][1]+A[i+1][j][1];

     A[i][j][3]=0;              

}

     else

     {

     A[i][j][1]=A[i][j][1]+A[i+1][j+1][1];

     A[i][j][3]=1;            //10来判断是否通过,方便最后计算

}

}                                  //从最后一层开始,每两个比较,更大的加到上面一节,依次判断相加,到最后一行就是最大权值

cout<<A[1][1][1]<<endl;

int j=1;

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

{

cout<<A[i][j][2]<<" ";

j=j+A[i][j][3];                //以之前判断的是否通过得出下一各数是下一行第几个

}

cout<<A[n][j][2];

return 0;

}

 

五、 调试与测试

1. 在调试过程中,需要验证算法是否正确,设计以下测试数据,并观察打印的结果。

     

                                 9         

                                  12   15       

                                10   6   8     

                              2   18   9   5   

                           19   7   10   4   16

六、 分析与总结

1. 从测试结果看,在这一组数据的运算中,能得到最大权值及其路径,且一切正常。

2. 但是当数据复杂度太大时,因为int型的容量问题,会导致无法算的结果。

3.  在这一题中,充分运用了图论中树的知识,逐步运算并标记。

 

   

                 

 

题2:数字排序 (ID: 1002 )

一、 问题描述

 

给定n个整数,请统计出每个整数出现的次数,按出现次数从多到少的顺序输出。

 

二、 问题分析

  

给定了整数个数,所以可以使用数组解决问题,在数组中进行统计,并根据数的个数来排序输出。

 

三、 算法分析

 

自行编写数组中的使用的排序算法及计数算法,然后进行相应的运算得出结果。设置两个数组一一对应,对每一个输入的数字进行for循环计数,因为结果中需要对一些重复的数进行删除,所以可以在计算个数时,把多于1的数字对应的计数数组中值赋值为0

 

四、 详细设计(从算法到程序)

 

1. 主模块设计

a. 设计一个数组和原数组一样用于排序,再设计一个数组大小和原数组一样,但是其中的元素都为0,为计数数组。

b. 先对输入的数组进行计数,利用二重for循环对每一个数都计数,然后再进行一次循环,把重复的数删除(即将个数记为0)。

c. 根据个数进行排序,并且因为存在个数相同的情况,所以在排序中添加一个对数字大小的判断,把小数排在前面。

d. 输出,把对应计数数组不为0的数进行输出,输出数字+空格+个数。

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

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

{

if(C[j]<C[j+1])

{

int t,s;

t=C[j+1];

C[j+1]=C[j];

C[j]=t;

s=B[j+1];

B[j+1]=B[j];

B[j]=s;                             //将各个数字按照个数进行排列

}

}

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

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

{

if(C[i]==C[j])

{

if(B[i]<B[j])

{

int t,s;

t=C[i];

C[i]=C[j];

C[j]=t;

s=B[i];

B[i]=B[j];

B[j]=s;

}

}

}

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

{

if(C[i]!=0)

cout<<B[i]<<" "<<C[i]<<endl;            //输出个数不为0的数

else

continue;

}

五、 调试与测试

1. 验证是否对于多个出现次数相同的数字,对于负数是否成立。设计以下几组数据:

 

112

5 2 3 3 1 3 4 2 5 2 3 5

     (2)9

     -1 2 5 7 7 8 8 -1 -9

     314

 -2 -2 -5 -5 5 6 7 -8 1 -1 -2 0 5 8          

                

六、 分析与总结

1. 对于三组数据,程序都能正常运行得出答案,并且不会出现重复输出的问题,说明程序算法合理。

2. 可以发现,此算法是对所有出现过的数字进行计数并排序,这样会比较复杂,需要对重复的数字进行处理,但是能存储较多数据,而如果采用下标的形式,即先设置一个长数组,将题目的输入看成是这个数组的下标,然后计数就不用处理重复数字了,但是这样无论是算哪一组数据都需要使用一个长数组,对于一些简单的问题可能会使问题更复杂。

 

 

 

题3:日历问题 (ID: 1006 )

  • 5
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值