作者yauhh (哟)
看板Programming
标题Re: [请益] 徵求强者解决程式难题
时间Fri Dec 9 00:19:29 2011
※ 引述《imorgan (i。摩根)》之铭言:
: 需求:
: 1. 1~50任意选出25各数字成为一组(代号a$),剩余25各数字为该组剩余数(代号b$)
: 2. 共需20组a1~a20(与相对应之b1~b20)
: 3. 以a来讲,总共会产生500各数字(25*20=500)
: 4. 以a来讲,1~50每各数字出现次数为10次(50*10=500)
: 5. 以a来讲,碰撞次数限制为4~6
: 碰撞定义:任意两组号码,同时出现在一组a中称为一次。
: 根据此一定义,任意两各数字 in 20组a中,碰撞次数n范围:0<=n<=10
: 碰撞举例:
: 有一组a1产出为(1,2,3,4,5,...,25)
: (1,2)的碰撞次数为1次,(1,3)(1,4)(1,5)...(24,25)亦同
: 6. 呈现上述20组a与其对应之20组b,共20*25=500各数字(与其对应各组剩余b),统计并
: 呈现所有碰撞组合之次数
你这个难题,我用Prolog写了一点点如下: (SWI-Prolog)
univ(U) :- numlist(1, 50, U). % universe 就是 1~50 而已
count(_N, 1). % 一句废话,对任何东西计算一次, 得数目为 1
% 从 List 中挑走 N 个, 得子串列为 Part, 剩余串列为 Rest.
select(0, List, [], List) :- !.
select(N, [H|T], [H|Part], Rest) :-
N1 is N-1, select(N1, T, Part, Rest), length([H|Part], N).
select(N, [H|T], Part, [H|Rest]) :-
select(N, T, Part, Rest), length(Part, N).
% 将 List 平分, 分配的每份子串列之长度必为 Length.
divide(List, Length, [List]) :- length(List, Length), !.
divide(List, Length, [Part|Result]) :-
select(Length, List, Part, Rest),
divide(Rest, Length, Result).
然後使用以下查询就可以得到左半A组资料:
(在测试时写错了,只弄出10组,速度快; 改为产生A20则费比较多时间.)
univ(U), % 令 U = {1, 2, ..., 50},
repeat_list(U, 10, U10), % 收集10份U的内容,
length(U, Lu), Lhf is Lu / 2, divide(U10, Lhf, A20), %将U10分为20组A,
bagof(XYs,
(member(An, A20), % 确认每个An组包含的项目皆独一,
forall((member(A, An), select(A, An, Am)), not(member(A, Am))),
bagof((X,Y), (member(X, An), member(Y, An), X < Y), XYs)),
XYss), % 并收集所有的成对号码,
flatten(XYss, XYs1), % 合并为A组全部的成对号码.
map_list_to_pairs(count, XYs1, Ps), % 将每个成对号码都数一次,
transpose_pairs(Ps, Tps), keysort(Tps, Sps), group_pairs_by_key(Sps, Gsps),
% 数算的结果整理成 "配对 - 数算次数" 的集合.
forall((member(_-Cs, Gsps), length(Cs, Lcs)), (Lcs = 4; Lcs = 5; Lcs = 6)),
% 确认每个成对数字的数算次数为 {4, 5, 6} 之一,
bagof(Assoc-Lcs, (member(Assoc-Cs, Gsps), length(Cs, Lcs)), Assocs),
% 并将每个成对数字的出现次数汇总, ("配对 - 出现次数")
transpose_pairs(Assocs, Scossa), keysort(Scossa, SScossa),
group_pairs_by_key(SScossa, Gscossa),
% 汇总结果还可以翻转再汇总为 "出现次数 - 各种配对情况" 的对应表.
% 印出A组内容,
nl, write('Left set:'), nl,
write(A20),
% 印出每个配对的出现次数,
nl, write('Number of associating items:'), nl,
write(Assocs), nl,
% 最後印出每个出现次数的配对案例数目, 完成.
nl, write('Statistics of associtation:'), nl,
write(Gscossa),
foreach(member(Times-Instances, Gscossa),
(length(Instances, Li),
nl, write(Times), write(': '), write(Li), write(' occurrence'), nl)).
--
/yau
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 61.231.67.186
1F:推 aceldama:15k! 15k! 24.176.222.26 12/09 04:26
2F:推 MOONRAKER:PROLOG赞 218.160.182.20 12/09 08:12
3F:→ yauhh:可是大资料量的产生,很慢,怎?办 101.8.90.125 12/09 08:51
4F:→ MOONRAKER:PROLOG那麽高阶 慢也没办法 |D 59.120.49.163 12/09 19:50
5F:→ yauhh:应该可以找得到跑比较快的写法... 61.231.67.186 12/09 20:03