《算法设计与分析》实验报告(二)之m钱买n鸡

二、实验内容

问题描述:我国古代数学家张丘建在《算经》中出了一道题“鸡翁一,值钱五;鸡母”一,值钱三;鸡雏三,值钱一。百钱买百鸡,问鸡翁、鸡母、鸡雏各几何?”。现在假定各鸡种的价格不变,拥有的钱数为m,需要购买的鸡数为n,试求出所有可能的购买方案总数和每种方案详情。

输入:每行对应一个测试样例,每一行包含2个数字,分别为n和m。

输出:输出可能购买方案总数,并输出每种方案详情。

进一步要求:先用常规嵌套循环解决,并验证当输入n=m=10000时的程序执行时间。在此基础上改进算法,提高算法时间复杂度。

程序代码:

#include<stdio.h>

int main()

{

    int N, M, n1, n2, n3, iCount = 0,k=1;//n1,n2,n3分别为鸡翁、鸡母、鸡雏的数目;拥有的钱数M,需购买鸡数N

    printf("请输入拥有的总钱数以及需购买的鸡数(注:输入‘-1’表示完成输入)\n");

   scanf("%d %d", &N, &M);

   while (N != -1) //-1:表示输入结束

   {

       iCount = 0;

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

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

              for (n3 = 0; n3 < N; n3++)//枚举对象三元组

                  if ((n1 + n2 + n3 == N) && (5 * n1 + 3 * n2 + n3 / 3.0 == M))//验证

                     iCount++;

       printf("共有%d种可行方案\r\n", iCount);

       scanf("%d%d", &N, &M);

   }

   for (n1 = 0; n1 <= 20; n1++)

       for (n2 = 0; n2 <= 33; n2++)

          for (n3 = 3; n3 <= 99; n3++)

              if (n1 * 5 + n2 * 3 + n3 / 3 == 100)

                 if (n1 + n2 + n3 == 100)

                     if (n3 % 3 == 0)

                     {

                     printf("方案% d:", k++);

                         printf("鸡翁:%d只,鸡母:%只,鸡雏:%d只 \n", n1, n2, n3);

                     }

   return 0;

}

程序测试及运行结果:

分析与讨论:

首先设n1,n2,n3分别为鸡翁、鸡母、鸡雏的数量。

由于题中条件的限制,我们可以估算出公鸡,母鸡,小鸡的数量范围。

由于题中条件的限制,即:

若全买公鸡,最多买100/5=20只,显然:0<x<20;

同理:0<y<33 0<z<100;

约束条件:x+y+z=100且 5x+3y+z/3=100且小鸡数量是3的倍数;

若用上面算法,需要枚举尝试20*33*100=66000次,算法的效率太低。因此我们将算法加以改进:即:在公鸡(x),母鸡(y)数量确定后,根据总数100只,小鸡的数量z也就确定为:z=100一x-y,无需再对小鸡的数量进行枚举,此时的约束条件:5x+3y+z/3=100 且小鸡的数量是3的倍数,这样只需枚举20*34=660次。

由上述实例可以看出,枚举法是蛮力策略的一种变现形式,也是一种使用非常普遍的思维方法。然而对于同一个问题,可以选择不同的美居范围,不同的枚举对象,这样解决问题的效率差别可能会很大。所以选择合适的方法会让解决问题的效率大大提高。

  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
设计分析: 最长公共子序列问题(Longest Common Subsequence,LCS)是一个经典的计算机科学问题,其目标是找到两个序列中最长的公共子序列。例如,对于序列 S1 = "ABCDGH" 和序列 S2 = "AEDFHR",它们的最长公共子序列为 "ADH"。该问题可以用动态规划法求解。 算法描述: 我们可以定义一个维数组 dp,其中 dp[i][j] 表示序列 S1 中前 i 个字符和序列 S2 中前 j 个字符的最长公共子序列的长度。然后,我们可以通过以下方式递推地计算 dp 数组: 当 i=0 或 j=0 时,dp[i][j] = 0。 当 S1[i-1] = S2[j-1] 时,dp[i][j] = dp[i-1][j-1] + 1。 当 S1[i-1] != S2[j-1] 时,dp[i][j] = max(dp[i-1][j], dp[i][j-1])。 最后,dp[m][n] 就是序列 S1 和序列 S2 的最长公共子序列的长度。 程序: 下面是一个使用 Python 编写的实现代码: ```python def longest_common_subsequence(s1, s2): m, n = len(s1), len(s2) dp = [[0] * (n+1) for _ in range(m+1)] for i in range(1, m+1): for j in range(1, n+1): if s1[i-1] == s2[j-1]: dp[i][j] = dp[i-1][j-1] + 1 else: dp[i][j] = max(dp[i-1][j], dp[i][j-1]) return dp[m][n] ``` 测试分析与总结: 我们可以使用一些测试数据来验证上述算法的正确性,例如: s1 = "ABCDGH" s2 = "AEDFHR" 最长公共子序列为 "ADH",其长度为 3。 s1 = "AGGTAB" s2 = "GXTXAYB" 最长公共子序列为 "GTAB",其长度为 4。 通过测试数据的验证,我们可以看到上述算法的正确性。另外,通过对算法的时间复杂度分析,我们可以得出该算法的时间复杂度为 O(mn),其中 m 和 n 分别是两个序列的长度。因此,我们可以得出结论:动态规划法是求解最长公共子序列问题的有效算法

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

了一li

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值