erlang 入门练习 顺序编程一

本文是Erlang入门系列的第一篇,重点介绍了顺序编程的基础练习,包括运动员分组、信用卡校验、第39级台阶问题以及颠倒的价牌问题的解决方案。通过实例展示了Erlang在解决逻辑和数学问题时的简洁性和效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

erlang 入门练习 顺序编程一

  • 目前只学到顺序编程, 其余个人认为真正的精髓OTP 并发,后期学习
  • 找了些带有逻辑应用题来练练手,熟悉语法和erlang多用的尾递归思维

1.运动员分组

有N个人参加100米短跑比赛。跑道为8条。程序的任务是按照尽量使每组的人数相差最少的原则分组。
例如:
N=8时,分成1组即可。
N=9时,分成2组:一组5人,一组4人。
N=25时,分4组:7、6、6、6。

请编程计算分组数字。
要求从标准输入获得一个正整数(1~100之间,不必考虑输入错误的情况),表示参赛的人数。
程序输出每个组的人数。从大到小顺序输出,每个数字一行。

比如,
用户输入:25
程序输出:
7
6
6
6

trainer(Num) ->
    Lines = (Num+7) div 8,
    LessNum = Num div Lines,
    Rest = Num rem Lines,
    get_each_trainer(LessNum, Rest, Lines).

get_each_trainer(_LessNum, 0, 0) ->
    io:format("");
get_each_trainer(LessNum, 0, Lines) ->
    io:format("~p~n", [LessNum]),
    get_each_trainer(LessNum, 0, Lines - 1);
get_each_trainer(LessNum, Rest, Lines) ->
    io:format("~p~n", [LessNum+1]),
    get_each_trainer(LessNum, Rest - 1, Lines-1).

2.信用卡校验

当你输入信用卡号码的时候,有没有担心输错了而造成损失呢?其实可以不必这么担心,因为并不是一个随便的信用卡号码都是合法的,它必须通过Luhn算法来验证通过。

该校验的过程:
1、从卡号最后一位数字开始,逆向将奇数位(1、3、5等等)相加。
2、从卡号最后一位数字开始,逆向将偶数位数字,先乘以2(如果乘积为两位数,则将其减去9),再求和。
3、将奇数位总和加上偶数位总和,结果应该可以被10整除。

例如,卡号是:5432123456788881

逆向奇数位为 4 2 2 4 6 8 8 1 和 = 35
逆向偶数位乘以2(有些要减去9)的结果:1 6 2 6 1 5 7 7,求和 = 35。
最后 35 + 35 = 70 可以被10整除,认定校验通过。

请编写一个程序,从标准输入获得卡号,然后判断是否校验通过。
通过显示:“成功”,否则显示“失败”。

比如,
输入:356827027232780
程序输出:成功

credit(Term) ->
   L = term_to_list(Term),
   io:format("~p~n", [L]),
   Sum = get_card_sum(reverse(L)),
   case Sum rem 10 =:= 0 of
       true -> {check_OK};
       false -> {check_NG}
   end.

term_to_list(Term) ->
    case is_number(Term) of
        true -> split_term(Term);
        false -> []
    end.

split_term(Term) ->
    split_term(Term, []).

split_term(0, L) ->
    L;
split_term(Term, L) ->
    split_term(Term div 10, [Term rem 10|L]).

reverse(Rev) ->
       reverse(Rev, []).

reverse([], Rev) ->
    Rev;
reverse([H|T], Rev) ->
    reverse(T, [H|Rev]).

get_card_sum(L) ->
    get_card_sum(L, 0, 0, 1).

get_card_sum([], Odd, Even, _Timers) ->
    io:format("Odd=~p, Even=~p~n", [Odd, Even]),
    Odd+Even;
get_card_sum([H|T], Odd, Even, Times) ->
    case Times rem 2 =:= 0 of
        true -> case H*2 >= 10 of
                    true -> get_card_sum(T, Odd, Even + H*2-9, Times + 1);
                    false -> get_card_sum(T, Odd, Even + H*2, Times + 1)
                end;
        false -> get_card_sum(T, Odd+ H, Even, Times +1)
    end.

3.第39级台阶

小明刚刚看完电影《第39级台阶》,离开电影院的时候,他数了数礼堂前的台阶数,恰好是39级!

站在台阶前,他突然又想着一个问题:

如果我每一步只能迈上1个或2个台阶。先迈左脚,然后左右交替,最后一步是迈右脚,也就是说一共要走偶数步。那么,上完39级台阶,有多少种不同的上法呢?

请你利用计算机的优势,帮助小明寻找答案。

要求提交的是一个整数。
注意:不要提交解答过程,或其它的辅助说明文字。

dfs() ->
    put(count, 0),
    dfs(0, 0),
    io:format("~p~n", [get(count)]).

dfs(39, Step) ->
    case Step rem 2 == 0 of
        true -> addcount();
        false -> []
    end;
dfs(Sum, _Step)
    when Sum > 39 ->
        [];
dfs(Sum, Step) ->
    dfs(Sum + 1, Step + 1),
    dfs(Sum + 2, Step + 1).

addcount() ->
    Count = get(count),
    put(count, Count+1).

4.颠倒的价牌

小李的店里专卖其它店中下架的样品电视机,可称为:样品电视专卖店。

其标价都是4位数字(即千元不等)。

小李为了标价清晰、方便,使用了预制的类似数码管的标价签,只要用颜色笔涂数字就可以了(参见p1.jpg)。

这种价牌有个特点,对一些数字,倒过来看也是合理的数字。如:1 2 5 6 8 9 0 都可以。这样一来,如果牌子挂倒了,有可能完全变成了另一个价格,比如:1958 倒着挂就是:8561,差了几千元啊!!

当然,多数情况不能倒读,比如,1110 就不能倒过来,因为0不能作为开始数字。

有一天,悲剧终于发生了。某个店员不小心把店里的某两个价格牌给挂倒了。并且这两个价格牌的电视机都卖出去了!

庆幸的是价格出入不大,其中一个价牌赔了2百多,另一个价牌却赚了8百多,综合起来,反而多赚了558元。

请根据这些信息计算:赔钱的那个价牌正确的价格应该是多少?

答案是一个4位的整数,请通过浏览器直接提交该数字。
注意:不要提交解答过程,或其它辅助说明类的内容。

9088

%% ==================== 列表推导==========
negative() ->
    L1 = [0,1,2,5,6,8,9],
    L2 = [0,1,2,5,9,8,6],

    Pos = [A*1000+B*100+C*10+D*1 || A<-L1, B<-L1, C<-L1, D<-L1],
    Neg = [I*1+J*10+K*100+L*1000 || I<-L2, J<-L2, K<-L2, L<-L2],

    PN2 = getPN(Pos, Neg, 2),
    PN8 = getPN(Pos, Neg, 8),
    % Print = fun(P, N) -> io:format("P=~p N=~p ~p    ", [P, N, P-N]) end,
    % [Print(P, N) || {P, N} <- PN2],
    % io:format("~n~n"),
    % [Print(P, N) || {P, N} <- PN8],
    [{PH2, NH2, PH8, NH8} || {PH2, NH2} <- PN2, {PH8, NH8} <- PN8, (PH2 - NH2) + (PH8 - NH8) == -558].

getPN(Pos, Neg, FindWhat) ->
    getPN(Pos, Neg, FindWhat, []).

getPN([], [], _FindWhat, Res) ->
    Res;
getPN([PH|PT], [NH|NT], FindWhat, Res)
    when PH >= 1000, NH >= 1000 ->
    if
        FindWhat == 2 ->
            case PH - NH >= 200 andalso PH - NH =< 299 of
                true -> getPN(PT, NT, FindWhat, [{PH, NH}|Res]);
                false -> getPN(PT, NT, FindWhat, Res)
        end;
        FindWhat == 8 ->
            case PH - NH =< -800 andalso PH - NH >= -899 of
                true -> getPN(PT, NT, FindWhat, [{PH, NH}|Res]);
                false -> getPN(PT, NT, FindWhat, Res)
        end;
        true -> [{0, 0}]
    end;
getPN([_PH|PT], [_NH|NT], FindWhat, Res) ->
    getPN(PT, NT, FindWhat, Res).

使用erlang的列表推导的功能, 简化的实现方式。 要善用列表推倒,比拿erlang 实现for循环再套fun()函数要好用多了。

如有错误请指正。


[1]: http://blog.youkuaiyun.com/junwei_yu/article/details/21980187 原网址由Java实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值