算法学习笔记(三)问题的转化与高精度运算

问题:设购票点没有任何的零钱,票价50美元,现有m人手持50美元,n人手持100美元,求这样m+n个人构成的队伍有多少种排队方法可以使得整个售票过程不中断。


分析:对于这个问题,经过简单的模拟可以发现,每个手持100的前面必须有一个手持50的,同样如果有k个手持100的连续出现,则前面至少连续k次50。

       这样一来,可以设手持50元的为+1,手持100元的为-1,设ai为为第i个人所对应的值,则问题转化为数组的部分和a1+a2+...+ak≥0,其中k≤m+n,为了求这样的数列的个数,需要使用组合数学的相关知识,这个问题可以使用现成的结论,第n个Catalan数,公式为:

       wKioL1QjiALRhjQ6AAAX2RPgzAA066.jpg

       在运算时,要特别注意m<n的情况,在这种情况下,无法满足要求。


算法实现:由于购票人数一般很多,这就带来了高精度运算的问题,不再能使用传统的运算方式。高精度运算的一种方法是把数据都转化为字符串,再对字符串定义运算。

   ①将数据转化为字符串

   将数据转化为字符串的算法是十分有效的,尤其在单片机的编程当中,一般的算法是将整数从高位到低位顺次存入一个字符数组,这时字符数组所存的数据是反的,这时候需要再设定一个数组将其反过来,通过查阅资料,发现了一种比较号的算法,它的亮点是①充分利用i++的先运算后++特性简化代码,②省略对位数的判断,而采用while(n)判断所有位数是不是都已经取完,③在字符数组尾部赋0从而保证字符串在最后一个有效位后结束。代码如下:

void NumToString(int n, char* s)
{
    int i,j,temp[8]; //临时数组,先把数位存入其中,倒序
    if(n == 0)
    {
        s[0] = '0';
        s[1] = 0; //在有效位之后添加\0
        return;
    }
    i = 0;
    while(n) //判断有没有取完所有位
    {
        temp[i++] = n % 10; //先存入,后i++
        n /= 10;
    }
    i -= 1;
    j = 0;
    while(i >= 0)
        s[j++] = temp[i--] + '0'; //将倒序的数组正序存入s数组,s数组存有最终结果
    s[j] = 0;
}

    ②重新定义字符串的运算,以乘法为例,算法如下:

void mul(char* m, char* n, char* res)
{
    int i,j,len1,len2;
    len1 = strlen(m);
    len2 = strlen(n);
    int *r = new int[len1 + len2 + 1]; //乘积的长度,例如两位乘以两位,最多为5位,因此多加1
    for(i = 0; i <= len1 + len2; i++) r[i] = 0; //初始化乘积存储数组
    for(i = 0; i < len1; i++)
        for(j = 0; j < len2; j++)
            r[i + j + 1] += (m[i] - '0')*(n[j] - '0'); //依次从最高位、次高位直至最低位进行运算,注意,这里的最高位实际为次高位,因为
                                                       //真正的最高位只能通过进位获得,而不是通过乘运算
    for(i = len1 + len2 - 1; i >=1; i--) //从最低位开始处理进位
    {
        if(r[i] > 9) 
        {
            int temp = r[i] / 10; //储存进位数
            r[i] %= 10; //将进位后的数组存在这一位
            r[i-1] += temp; //进位运算,同时处理r[0]这一位(进位可能到达的最高位,没有则为0)
        }
    }
    for(i = 0; i<len1+len2;i++) cout << r[i] << " ";
    cout << endl;
    //经过这样的运算,将会得到数据字符串,其中最高位在r[0]内,最低位在r[len1+len2-1]内
    for(i = 0; i < len1+len2; i++) //判断是否乘积为0,为0则i会自加到len1+len2
        if(r[i] != 0) break;
    if(i == len1 + len2)
    {
        res[0] = '0';
        res[1] = 0;
        return;
    }
    //如果乘积不为0,会进行下面的运算,顺次将r[0]到r[len1+len2-1]存入res[0]到res[len1+len2-1]
    j = 0;
    while(i < len1 + len2)
    {
        res[j++] = r[i++] + '0';
    }
    res[j] = 0;
    delete[] r;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
逻辑结构:描述数据元素之间的逻辑关系,如线性结构(如数组、链表)、树形结构(如二叉树、堆、B树)、图结构(有向图、无向图等)以及集合和队列等抽象数据类型。 存储结构(物理结构):描述数据在计算机中如何具体存储。例如,数组的连续存储,链表的动态分配节点,树和图的邻接矩阵或邻接表表示等。 基本操作:针对每种数据结构,定义了一系列基本的操作,包括但不限于插入、删除、查找、更新、遍历等,并分析这些操作的时间复杂度和空间复杂度。 算法算法设计:研究如何将解决问题的步骤形式化为一系列指令,使得计算机可以执行以求解问题算法特性:包括输入、输出、有穷性、确定性和可行性。即一个有效的算法必须能在有限步骤内结束,并且对于给定的输入产生唯一的确定输出。 算法分类:排序算法(如冒泡排序、快速排序、归并排序),查找算法(如顺序查找、二分查找、哈希查找),图论算法(如Dijkstra最短路径算法、Floyd-Warshall算法、Prim最小生成树算法),动态规划,贪心算法,回溯法,分支限界法等。 算法分析:通过数学方法分析算法的时间复杂度(运行时间随数据规模增长的速度)和空间复杂度(所需内存大小)来评估其效率。 学习算法与数据结构不仅有助于理解程序的内部工作原理,更能帮助开发人员编写出效、稳定和易于维护的软件系统。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值