Update all new Tasks
This commit is contained in:
parent
00a190b0a6
commit
91df62d461
5697 changed files with 93386 additions and 804 deletions
67
Task/Paraffins/00DESCRIPTION
Normal file
67
Task/Paraffins/00DESCRIPTION
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
This organic chemistry task is essentially to implement a tree enumeration algorithm.
|
||||
|
||||
The problem is to enumerate, without repetitions and in order of increasing size, all possible paraffin molecules (or [[wp:alkane|alkane]]s). Paraffins are built up using only carbon, which has 4 bonds and hydrogen, which has 1. All bonds for each atom must be used, so it is easiest to think of an alkane as linked carbon atoms forming the "backbone" structure, with adding hydrogens linking the remaining unused bonds.
|
||||
|
||||
In a paraffin one is allowed neither double bonds (two bonds between the same pair of atoms) nor cycles of linked carbons, so all paraffins with <em>n</em> carbon atoms share the empirical formula C<sub>n</sub>H<sub>2n+2</sub> but for all n >= 4 there are several distinct molecules ("isomers") with the same formula but different structures. The number of isomers rises rather rapidly with n. In counting isomers it should be borne in mind that the four bond positions on a given carbon atom can be freely interchanged and bonds rotated (including 3-D "out of the paper" rotations when you are looking at a flat diagram), so rotations or reorientations of parts of the molecule (without breaking bonds) do not give different isomers. So what seem at first to be different molecules may in fact turn out to be different orientations of the same molecule.
|
||||
|
||||
For example with n = 3 there is only 1 way of linking the carbons despite the different orientations you can draw the molecule in; and with n = 4 there are 2 configurations, a straight chain: (CH<sub>3</sub>)(CH<sub>2</sub>)(CH<sub>2</sub>)(CH<sub>3</sub>) and a branched chain: (CH<sub>3</sub>)(CH(CH<sub>3</sub>))(CH<sub>3</sub>). Due to bond rotations it doesn't matter which direction the branch points in. The phenomenon of "stereo-isomerism" (a molecule being different from its mirror image due to the actual 3-D arrangement of bonds) is ignored for the purpose of this task.
|
||||
|
||||
The input is just the number 'n' of carbon atoms of a molecule, like 17. The output is how many different different paraffins there are with 'n' carbon atoms (like 24_894 if n = 17).
|
||||
|
||||
The sequence of those results is visible in the [[oeis:A000602|Sloane encyclopedia]]. The sequence is (the index starts from 0, and represents the number of carbon atoms):
|
||||
|
||||
1, 1, 1, 1, 2, 3, 5, 9, 18, 35, 75, 159, 355, 802, 1858, 4347, 10359,
|
||||
24894, 60523, 148284, 366319, 910726, 2278658, 5731580, 14490245,
|
||||
36797588, 93839412, 240215803, 617105614, 1590507121, 4111846763,
|
||||
10660307791, 27711253769, ...
|
||||
|
||||
'''Extra credit'''
|
||||
|
||||
Show the paraffins in some way. A flat 1D representation, with arrays or lists is enough, like:
|
||||
|
||||
<lang haskell>*Main> all_paraffins 1
|
||||
[CCP H H H H]
|
||||
*Main> all_paraffins 2
|
||||
[BCP (C H H H) (C H H H)]
|
||||
*Main> all_paraffins 3
|
||||
[CCP H H (C H H H) (C H H H)]
|
||||
*Main> all_paraffins 4
|
||||
[BCP (C H H (C H H H)) (C H H (C H H H)),CCP H (C H H H) (C H H H)
|
||||
(C H H H)]
|
||||
*Main> all_paraffins 5
|
||||
[CCP H H (C H H (C H H H)) (C H H (C H H H)),CCP H (C H H H)
|
||||
(C H H H) (C H H (C H H H)),CCP (C H H H) (C H H H) (C H H H)
|
||||
(C H H H)]
|
||||
*Main> all_paraffins 6
|
||||
[BCP (C H H (C H H (C H H H))) (C H H (C H H (C H H H))),BCP
|
||||
(C H H (C H H (C H H H))) (C H (C H H H) (C H H H)),BCP (C H
|
||||
(C H H H) (C H H H)) (C H (C H H H) (C H H H)),CCP H (C H H H)
|
||||
(C H H (C H H H)) (C H H (C H H H)),CCP (C H H H) (C H H H)
|
||||
(C H H H) (C H H (C H H H))]</lang>
|
||||
|
||||
Showing a basic 2D ASCII-art representation of the paraffines is better, like (molecule names aren't necessary):
|
||||
<pre> Methane Ethane Propane Iso-butane
|
||||
|
||||
H H H H H H H H H
|
||||
| | | | | | | | |
|
||||
H - C - H H - C - C - H H - C - C - C - H H - C - C - C - H
|
||||
| | | | | | | | |
|
||||
H H H H H H H | H
|
||||
|
|
||||
H - C - H
|
||||
|
|
||||
H</pre>
|
||||
|
||||
'''Links'''
|
||||
|
||||
A paper that explains the problem and its solution in a functional language:
|
||||
http://www.cs.wright.edu/~tkprasad/courses/cs776/paraffins-turner.pdf
|
||||
|
||||
A Haskell implementation:
|
||||
http://darcs.brianweb.net/nofib/imaginary/paraffins/Main.hs ◄── dead link.
|
||||
|
||||
A Scheme implementation:
|
||||
http://www.ccs.neu.edu/home/will/Twobit/src/paraffins.scm
|
||||
|
||||
A Fortress implementation:
|
||||
http://java.net/projects/projectfortress/sources/sources/content/ProjectFortress/demos/turnersParaffins0.fss?rev=3005
|
||||
115
Task/Paraffins/C/paraffins-1.c
Normal file
115
Task/Paraffins/C/paraffins-1.c
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#define MAX_N 33 /* max number of tree nodes */
|
||||
#define BRANCH 4 /* max number of edges a single node can have */
|
||||
|
||||
/* The basic idea: a paraffin molecule can be thought as a simple tree
|
||||
with each node being a carbon atom. Counting molecules is thus the
|
||||
problem of counting free (unrooted) trees of given number of nodes.
|
||||
|
||||
An unrooted tree needs to be uniquely represented, so we need a way
|
||||
to cannonicalize equivalent free trees. For that, we need to first
|
||||
define the cannonical form of rooted trees. Since rooted trees can
|
||||
be constructed by a root node and up to BRANCH rooted subtrees that
|
||||
are arranged in some definite order, we can define it thusly:
|
||||
* Given the root of a tree, the weight of each of its branches is
|
||||
the number of nodes contained in that branch;
|
||||
* A cannonical rooted tree would have its direct subtrees ordered
|
||||
in descending order by weight;
|
||||
* In case multiple subtrees are the same weight, they are ordered
|
||||
by some unstated, but definite, order (this code doesn't really
|
||||
care what the ordering is; it only counts the number of choices
|
||||
in such a case, not enumerating individual trees.)
|
||||
|
||||
A rooted tree of N nodes can then be constructed by adding smaller,
|
||||
cannonical rooted trees to a root node, such that:
|
||||
* Each subtree has fewer than BRANCH branches (since it must have
|
||||
an empty slot for an edge to connect to the new root);
|
||||
* Weight of those subtrees added later are no higher than earlier
|
||||
ones;
|
||||
* Their weight total N-1.
|
||||
A rooted tree so constructed would be itself cannonical.
|
||||
|
||||
For an unrooted tree, we can define the radius of any of its nodes:
|
||||
it's the maximum weight of any of the subtrees if this node is used
|
||||
as the root. A node is the center of a tree if it has the smallest
|
||||
radius among all the nodes. A tree can have either one or two such
|
||||
centers; if two, they must be adjacent (cf. Knuth, tAoCP 2.3.4.4).
|
||||
|
||||
An important fact is that, a node in a tree is its sole center, IFF
|
||||
its radius times 2 is no greater than the sum of the weights of all
|
||||
branches (ibid). While we are making rooted trees, we can add such
|
||||
trees encountered to the count of cannonical unrooted trees.
|
||||
|
||||
A bi-centered unrooted tree with N nodes can be made by joining two
|
||||
trees, each with N/2 nodes and fewer than BRANCH subtrees, at root.
|
||||
The pair must be ordered in aforementioned implicit way so that the
|
||||
product is cannonical. */
|
||||
|
||||
typedef unsigned long long xint;
|
||||
#define FMT "llu"
|
||||
|
||||
xint rooted[MAX_N] = {1, 1, 0};
|
||||
xint unrooted[MAX_N] = {1, 1, 0};
|
||||
|
||||
/* choose k out of m possible values; chosen values may repeat, but the
|
||||
ordering of them does not matter. It's binomial(m + k - 1, k) */
|
||||
xint choose(xint m, xint k)
|
||||
{
|
||||
xint i, r;
|
||||
|
||||
if (k == 1) return m;
|
||||
for (r = m, i = 1; i < k; i++)
|
||||
r = r * (m + i) / (i + 1);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* constructing rooted trees of BR branches at root, with at most
|
||||
N radius, and SUM nodes in the partial tree already built. It's
|
||||
recursive, and CNT and L carry down the number of combinations
|
||||
and the tree radius already encountered. */
|
||||
void tree(xint br, xint n, xint cnt, xint sum, xint l)
|
||||
{
|
||||
xint b, c, m, s;
|
||||
|
||||
for (b = br + 1; b <= BRANCH; b++) {
|
||||
s = sum + (b - br) * n;
|
||||
if (s >= MAX_N) return;
|
||||
|
||||
/* First B of BR branches are all of weight n; the
|
||||
rest are at most of weight N-1 */
|
||||
c = choose(rooted[n], b - br) * cnt;
|
||||
|
||||
/* This partial tree is singly centered as is */
|
||||
if (l * 2 < s) unrooted[s] += c;
|
||||
|
||||
/* Trees saturate at root can't be used as building
|
||||
blocks for larger trees, so forget them */
|
||||
if (b == BRANCH) return;
|
||||
rooted[s] += c;
|
||||
|
||||
/* Build the rest of the branches */
|
||||
for (m = n; --m; ) tree(b, m, c, s, l);
|
||||
}
|
||||
}
|
||||
|
||||
void bicenter(int s)
|
||||
{
|
||||
if (s & 1) return;
|
||||
|
||||
/* Pick two of the half-size building blocks, allowing
|
||||
repetition. */
|
||||
unrooted[s] += rooted[s/2] * (rooted[s/2] + 1) / 2;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
xint n;
|
||||
for (n = 1; n < MAX_N; n++) {
|
||||
tree(0, n, 1, 1, n);
|
||||
bicenter(n);
|
||||
printf("%"FMT": %"FMT"\n", n, unrooted[n]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
106
Task/Paraffins/C/paraffins-2.c
Normal file
106
Task/Paraffins/C/paraffins-2.c
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
#include <gmp.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define MAX_BRANCH 4
|
||||
#define MAX_N 500
|
||||
|
||||
mpz_t bcache[MAX_N + 1];
|
||||
mpz_t ucache[MAX_N + 1];
|
||||
mpz_t *rcache[MAX_N + 1][MAX_BRANCH + 1];
|
||||
|
||||
mpz_t tmp1, tmp2;
|
||||
void choose(mpz_t r, mpz_t m, int k)
|
||||
{
|
||||
int i;
|
||||
mpz_set(r, m);
|
||||
|
||||
mpz_add_ui(tmp1, m, 1);
|
||||
for (i = 1; i < k; ) {
|
||||
mpz_mul(r, r, tmp1);
|
||||
mpz_divexact_ui(r, r, ++i);
|
||||
|
||||
if (i >= k) break;
|
||||
mpz_add_ui(tmp1, tmp1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
mpz_t rtmp1, rtmp2;
|
||||
void calc_rooted(mpz_t res, int n, int b, int r)
|
||||
{
|
||||
mpz_set_ui(res, 0);
|
||||
|
||||
if (n == 1 && b == 0 && r == 0) {
|
||||
mpz_set_ui(res, 1);
|
||||
return;
|
||||
} else if (n <= b || n <= r || n == 1 || b == 0 || r == 0)
|
||||
return;
|
||||
|
||||
int b1, r1;
|
||||
for (b1 = 1; b1 <= b && r * b1 < n; b1++) {
|
||||
choose(rtmp1, bcache[r], b1);
|
||||
mpz_set_ui(rtmp2, 0);
|
||||
for (r1 = 0; r1 < r && r1 + r * b1 < n; r1++)
|
||||
mpz_add(rtmp2, rtmp2, rcache[n - r * b1][b - b1][r1]);
|
||||
|
||||
mpz_addmul(res, rtmp1, rtmp2);
|
||||
}
|
||||
}
|
||||
|
||||
void calc_first_branch(int n)
|
||||
{
|
||||
int b, r;
|
||||
mpz_init_set_ui(bcache[n], 0);
|
||||
|
||||
for (b = 0; b < MAX_BRANCH; b++)
|
||||
for (r = 0; r < n; r++)
|
||||
mpz_add(bcache[n], bcache[n], rcache[n][b][r]);
|
||||
}
|
||||
|
||||
void calc_unrooted(int n)
|
||||
{
|
||||
int b, r;
|
||||
|
||||
for (b = 0; b <= MAX_BRANCH; b++) {
|
||||
mpz_t *p = malloc(sizeof(mpz_t) * n);
|
||||
rcache[n][b] = p;
|
||||
for (r = 0; r < n; r++) {
|
||||
mpz_init(p[r]);
|
||||
calc_rooted(p[r], n, b, r);
|
||||
}
|
||||
}
|
||||
|
||||
calc_first_branch(n);
|
||||
|
||||
mpz_init_set_ui(ucache[n], 0);
|
||||
for (r = 0; r * 2 < n; r++)
|
||||
for (b = 0; b <= MAX_BRANCH; b++)
|
||||
mpz_add(ucache[n], ucache[n], rcache[n][b][r]);
|
||||
|
||||
if (!(n & 1)) {
|
||||
mpz_add_ui(rtmp1, bcache[n/2], 1);
|
||||
mpz_mul(rtmp1, rtmp1, bcache[n/2]);
|
||||
mpz_divexact_ui(rtmp1, rtmp1, 2);
|
||||
mpz_add(ucache[n], ucache[n], rtmp1);
|
||||
}
|
||||
}
|
||||
|
||||
void init(void)
|
||||
{
|
||||
mpz_init(tmp1), mpz_init(tmp2);
|
||||
mpz_init(rtmp1), mpz_init(rtmp2);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
init();
|
||||
|
||||
for (i = 0; i <= MAX_N; i++) {
|
||||
calc_unrooted(i);
|
||||
gmp_printf("%d: %Zd\n", i, ucache[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
44
Task/Paraffins/D/paraffins.d
Normal file
44
Task/Paraffins/D/paraffins.d
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import std.stdio, std.bigint;
|
||||
|
||||
enum uint nMax = 250;
|
||||
enum uint nBranches = 4;
|
||||
|
||||
__gshared BigInt[nMax + 1] rooted = [1.BigInt, 1.BigInt /*...*/],
|
||||
unrooted = [1.BigInt, 1.BigInt /*...*/];
|
||||
|
||||
void tree(in uint br, in uint n, in uint l, in uint inSum,
|
||||
in BigInt cnt) nothrow {
|
||||
__gshared static BigInt[nBranches] c;
|
||||
|
||||
uint sum = inSum;
|
||||
foreach (immutable b; br + 1 .. nBranches + 1) {
|
||||
sum += n;
|
||||
if (sum > nMax || (l * 2 >= sum && b >= nBranches))
|
||||
return;
|
||||
if (b == br + 1) {
|
||||
c[br] = rooted[n] * cnt;
|
||||
} else {
|
||||
c[br] *= rooted[n] + b - br - 1;
|
||||
c[br] /= b - br;
|
||||
}
|
||||
if (l * 2 < sum)
|
||||
unrooted[sum] += c[br];
|
||||
if (b < nBranches)
|
||||
rooted[sum] += c[br];
|
||||
foreach_reverse (immutable m; 1 .. n)
|
||||
tree(b, m, l, sum, c[br]);
|
||||
}
|
||||
}
|
||||
|
||||
void bicenter(in uint s) nothrow {
|
||||
if ((s & 1) == 0)
|
||||
unrooted[s] += rooted[s / 2] * (rooted[s / 2] + 1) / 2;
|
||||
}
|
||||
|
||||
void main() {
|
||||
foreach (immutable n; 1 .. nMax + 1) {
|
||||
tree(0, n, n, 1, 1.BigInt);
|
||||
n.bicenter;
|
||||
writeln(n, ": ", unrooted[n]);
|
||||
}
|
||||
}
|
||||
61
Task/Paraffins/Go/paraffins.go
Normal file
61
Task/Paraffins/Go/paraffins.go
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
const branches = 4
|
||||
const nMax = 500
|
||||
|
||||
var rooted, unrooted [nMax + 1]big.Int
|
||||
var c [branches]big.Int
|
||||
var tmp = new(big.Int)
|
||||
var one = big.NewInt(1)
|
||||
|
||||
func tree(br, n, l, sum int, cnt *big.Int) {
|
||||
for b := br + 1; b <= branches; b++ {
|
||||
sum += n
|
||||
if sum > nMax {
|
||||
return
|
||||
}
|
||||
if l*2 >= sum && b >= branches {
|
||||
return
|
||||
}
|
||||
if b == br+1 {
|
||||
c[br].Mul(&rooted[n], cnt)
|
||||
} else {
|
||||
tmp.Add(&rooted[n], tmp.SetInt64(int64(b-br-1)))
|
||||
c[br].Mul(&c[br], tmp)
|
||||
c[br].Div(&c[br], tmp.SetInt64(int64(b-br)))
|
||||
}
|
||||
if l*2 < sum {
|
||||
unrooted[sum].Add(&unrooted[sum], &c[br])
|
||||
}
|
||||
if b < branches {
|
||||
rooted[sum].Add(&rooted[sum], &c[br])
|
||||
}
|
||||
for m := n - 1; m > 0; m-- {
|
||||
tree(b, m, l, sum, &c[br])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func bicenter(s int) {
|
||||
if s&1 == 0 {
|
||||
tmp.Rsh(tmp.Mul(&rooted[s/2], tmp.Add(&rooted[s/2], one)), 1)
|
||||
unrooted[s].Add(&unrooted[s], tmp)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
rooted[0].SetInt64(1)
|
||||
rooted[1].SetInt64(1)
|
||||
unrooted[0].SetInt64(1)
|
||||
unrooted[1].SetInt64(1)
|
||||
for n := 1; n <= nMax; n++ {
|
||||
tree(0, n, n, 1, big.NewInt(1))
|
||||
bicenter(n)
|
||||
fmt.Printf("%d: %d\n", n, &unrooted[n])
|
||||
}
|
||||
}
|
||||
32
Task/Paraffins/Haskell/paraffins.hs
Normal file
32
Task/Paraffins/Haskell/paraffins.hs
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import Data.Array
|
||||
|
||||
choose :: Integer -> Int -> Integer
|
||||
choose m k = let kk = toInteger k in (product [m..m+kk-1]) `div` (product [1..kk])
|
||||
|
||||
max_branches = 4
|
||||
max_nodes = 200
|
||||
|
||||
bcache = listArray (0, max_nodes)
|
||||
[sum[rcache!n!b!r | r <- [0..n], b <- [0..max_branches-1]] | n <- [0..max_nodes]]
|
||||
build_block = (bcache !)
|
||||
|
||||
rcache = listArray (0,max_nodes) [arr_b i | i <- [0..max_nodes]] where
|
||||
arr_b n = listArray(0,max_branches) [arr_r b n | b <- [0..max_branches]]
|
||||
arr_r b n = listArray(0,n) [rooted n b r | r <- [0..n]]
|
||||
|
||||
rooted 1 0 0 = 1
|
||||
rooted 1 _ _ = 0
|
||||
rooted _ 0 _ = 0
|
||||
rooted _ _ 0 = 0
|
||||
rooted n b r
|
||||
| (n <= b) || (n <= r) = 0
|
||||
| otherwise = sum [(firsts b1) * (rests b1) | b1 <- [1..b], r * b1 < n] where
|
||||
firsts = choose (build_block r)
|
||||
rests bb = sum [rcache!(n-r*bb)!(b - bb)!r1 | r1 <- [0..r-1], r1 < (n-r*bb)]
|
||||
|
||||
unrooted n = unicenter + bycenter where
|
||||
unicenter = sum [ rcache!n!b!r | b <- [0..max_branches], r <-[0..n], r * 2 < n]
|
||||
bycenter| odd n = 0
|
||||
| otherwise = x * (x + 1) `div` 2 where x = build_block (n `div` 2)
|
||||
|
||||
main = mapM_ print $ map (\x->(x, unrooted x)) [1..max_nodes]
|
||||
32
Task/Paraffins/J/paraffins-1.j
Normal file
32
Task/Paraffins/J/paraffins-1.j
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
part3=: ;@((<@([(],.(-+/"1))],.]+i.@(]-~1+<.@-:@-))"0 i.@>:@<.@%&3))
|
||||
|
||||
part4=: 3 :0
|
||||
ij=.; (,.]+i.@:(]-~1+[:<.3%~y-]))&.> i.1+<.y%4
|
||||
(,.y - +/"1) ; (<@(],"1 0 <.@-:@(y-[) (] + i.@>:@-) {:@] >. (>.-:y)-[)~+/)"1 ij
|
||||
)
|
||||
|
||||
c0=: */@:{
|
||||
c1=: 13 :'(*-:@(*>:))/y{~}:x'
|
||||
c2=: 13 :'(*-:@(*>:))~/y{~}.x'
|
||||
c3=: 13 :'3!2+y{~{.x'
|
||||
|
||||
radGenN=: [:;[:(],[:+/c0`c1`c2`c3@.(#.@(}.=}:)@[)"1)&.>/(<1x),~part3&.>@ i.@-
|
||||
|
||||
bcpGenN=: [: , 0 ,.~ -:@(*>:)@({~i.)
|
||||
|
||||
c11=: 13 :'*/(y{~0 1{x), -:(*>:)y{~{:x'
|
||||
c12=: 13 :'*/(y{~0 3{x), -:(*>:)y{~2{x'
|
||||
c13=: 13 :'*/(y{~{.x) , 3!2+ y{~{: x'
|
||||
c14=: 13 :'*/(y{~_2{.x), -:(*>:)y{~{.x'
|
||||
c15=: 13 :'*/ -:(*>:) y{~0 3{x'
|
||||
c16=: 13 :'*/(y{~{:x) , 3!2+ y{~{. x'
|
||||
c17=: 13 :'4!3+y{~{.x'
|
||||
|
||||
cassl=: c0`c11`c12`c13`c14`c15`c16`c17
|
||||
|
||||
ccpGenN=: 4 :0
|
||||
if. 0=y do. i.0 return. end.
|
||||
y{.2({.,0,}.) 0,+/@:(x cassl@.(#.@(}.=}:)@[)"1~[)@:part4"0 [1-.~i.y-1
|
||||
)
|
||||
|
||||
NofParaff=: {. radGenN ((ccpGenN +:) + bcpGenN ) 2&|+<.@-:
|
||||
7
Task/Paraffins/J/paraffins-2.j
Normal file
7
Task/Paraffins/J/paraffins-2.j
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
6 6 $ NofParaff 36
|
||||
1 1 1 1 2 3
|
||||
5 9 18 35 75 159
|
||||
355 802 1858 4347 10359 24894
|
||||
60523 148284 366319 910726 2278658 5731580
|
||||
14490245 36797588 93839412 240215803 617105614 1590507121
|
||||
4111846763 10660307791 27711253769 72214088660 188626236139 493782952902
|
||||
14
Task/Paraffins/Mathematica/paraffins.math
Normal file
14
Task/Paraffins/Mathematica/paraffins.math
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
G000602[n_] :=
|
||||
Block[{x},
|
||||
x*CycleIndexPolynomial[SymmetricGroup[4],
|
||||
Table[ComposeSeries[#, x^i + O[x]^(n + 1)], {i, 4}]] -
|
||||
CycleIndexPolynomial[SymmetricGroup[2],
|
||||
Table[ComposeSeries[# - 1, x^i + O[x]^(n + 1)], {i, 2}]] +
|
||||
ComposeSeries[#, x^2 + O[x]^(n + 1)] &@
|
||||
Fold[Series[
|
||||
1 + x/6 (#1^3 + 3 #1 ComposeSeries[#1, x^2 + O[x]^#2] +
|
||||
2 ComposeSeries[#1, x^3 + O[x]^#2]), {x, 0, #2}] &,
|
||||
1 + O[x], Range[n + 1]]];
|
||||
A000602[n_] := SeriesCoefficient[G000602[n], n];
|
||||
A000602List[n_] := CoefficientList[G000602[n], x];
|
||||
Grid@Transpose@{Range[0, 200], A000602List@200}
|
||||
88
Task/Paraffins/Pascal/paraffins.pascal
Normal file
88
Task/Paraffins/Pascal/paraffins.pascal
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
Program Paraffins;
|
||||
|
||||
uses
|
||||
gmp;
|
||||
|
||||
const
|
||||
max_n = 500;
|
||||
branch = 4;
|
||||
|
||||
var
|
||||
rooted, unrooted: array [0 .. max_n-1] of mpz_t;
|
||||
c: array [0 .. branch-1] of mpz_t;
|
||||
cnt, tmp: mpz_t;
|
||||
n: integer;
|
||||
fmt: pchar;
|
||||
sum: integer;
|
||||
|
||||
procedure tree(br, n, l: integer; sum: integer; cnt: mpz_t);
|
||||
var
|
||||
b, m: integer;
|
||||
begin
|
||||
for b := br + 1 to branch do
|
||||
begin
|
||||
sum := sum + n;
|
||||
if sum >= max_n then
|
||||
exit;
|
||||
|
||||
(* prevent unneeded long math *)
|
||||
if (l * 2 >= sum) and (b >= branch) then
|
||||
exit;
|
||||
|
||||
if b = (br + 1) then
|
||||
mpz_mul(c[br], rooted[n], cnt)
|
||||
else
|
||||
begin
|
||||
mpz_add_ui(tmp, rooted[n], b - br - 1);
|
||||
mpz_mul(c[br], c[br], tmp);
|
||||
mpz_divexact_ui(c[br], c[br], b - br);
|
||||
end;
|
||||
|
||||
if l * 2 < sum then
|
||||
mpz_add(unrooted[sum], unrooted[sum], c[br]);
|
||||
|
||||
if b < branch then
|
||||
begin
|
||||
mpz_add(rooted[sum], rooted[sum], c[br]);
|
||||
for m := n-1 downto 1 do
|
||||
tree(b, m, l, sum, c[br]);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure bicenter(s: integer);
|
||||
begin
|
||||
if odd(s) then
|
||||
exit;
|
||||
mpz_add_ui(tmp, rooted[s div 2], 1);
|
||||
mpz_mul(tmp, rooted[s div 2], tmp);
|
||||
mpz_tdiv_q_2exp(tmp, tmp, 1);
|
||||
|
||||
mpz_add(unrooted[s], unrooted[s], tmp);
|
||||
end;
|
||||
|
||||
begin
|
||||
for n := 0 to 1 do
|
||||
begin
|
||||
mpz_init_set_ui(rooted[n], 1);
|
||||
mpz_init_set_ui(unrooted[n], 1);
|
||||
end;
|
||||
for n := 2 to max_n-1 do
|
||||
begin
|
||||
mpz_init_set_ui(rooted[n], 0);
|
||||
mpz_init_set_ui(unrooted[n], 0);
|
||||
end;
|
||||
for n := 0 to BRANCH-1 do
|
||||
mpz_init(c[n]);
|
||||
|
||||
mpz_init(tmp);
|
||||
|
||||
mpz_init_set_ui(cnt, 1);
|
||||
sum := 1;
|
||||
for n := 1 to MAX_N do
|
||||
begin
|
||||
tree(0, n, n, sum, cnt);
|
||||
bicenter(n);
|
||||
mp_printf('%d: %Zd'+chr(13)+chr(10), n, @unrooted[n]);
|
||||
end;
|
||||
end.
|
||||
45
Task/Paraffins/Perl-6/paraffins.pl6
Normal file
45
Task/Paraffins/Perl-6/paraffins.pl6
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
sub count-unrooted-trees(Int $max-branches, Int $max-weight) {
|
||||
my @rooted = 1,1,0 xx $max-weight - 1;
|
||||
my @unrooted = 1,1,0 xx $max-weight - 1;
|
||||
|
||||
sub count-trees-with-centroid(Int $radius) {
|
||||
sub add-branches(
|
||||
Int $branches, # number of branches to add
|
||||
Int $w, # weight of heaviest branch to add
|
||||
Int $weight is copy, # accumulated weight of tree
|
||||
Int $choices is copy, # number of choices so far
|
||||
) {
|
||||
$choices *= @rooted[$w];
|
||||
for 1 .. $branches -> $b {
|
||||
($weight += $w) <= $max-weight or last;
|
||||
@unrooted[$weight] += $choices if $weight > 2*$radius;
|
||||
if $b < $branches {
|
||||
@rooted[$weight] += $choices;
|
||||
add-branches($branches - $b, $_, $weight, $choices) for 1 ..^ $w;
|
||||
$choices = $choices * (@rooted[$w] + $b) div ($b + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
add-branches($max-branches, $radius, 1, 1);
|
||||
}
|
||||
|
||||
sub count-trees-with-bicentroid(Int $weight) {
|
||||
if $weight %% 2 {
|
||||
my \halfs = @rooted[$weight div 2];
|
||||
@unrooted[$weight] += (halfs * (halfs + 1)) div 2;
|
||||
}
|
||||
}
|
||||
|
||||
gather {
|
||||
take 1;
|
||||
for 1 .. $max-weight {
|
||||
count-trees-with-centroid($_);
|
||||
count-trees-with-bicentroid($_);
|
||||
take @unrooted[$_];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
my constant N = 100;
|
||||
my @paraffins := count-unrooted-trees(4, N);
|
||||
say .fmt('%3d'), ': ', @paraffins[$_] for 1 .. 30, N;
|
||||
40
Task/Paraffins/Perl/paraffins.pl
Normal file
40
Task/Paraffins/Perl/paraffins.pl
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
use Math::GMPz;
|
||||
|
||||
my $nmax = 250;
|
||||
my $nbranches = 4;
|
||||
|
||||
my @rooted = map { Math::GMPz->new($_) } 1,1,(0) x $nmax;
|
||||
my @unrooted = map { Math::GMPz->new($_) } 1,1,(0) x $nmax;
|
||||
my @c = map { Math::GMPz->new(0) } 0 .. $nbranches-1;
|
||||
|
||||
sub tree {
|
||||
my($br, $n, $l, $sum, $cnt) = @_;
|
||||
for my $b ($br+1 .. $nbranches) {
|
||||
$sum += $n;
|
||||
return if $sum > $nmax || ($l*2 >= $sum && $b >= $nbranches);
|
||||
if ($b == $br+1) {
|
||||
$c[$br] = $rooted[$n] * $cnt;
|
||||
} else {
|
||||
$c[$br] *= $rooted[$n] + $b - $br - 1;
|
||||
$c[$br] /= $b - $br;
|
||||
}
|
||||
$unrooted[$sum] += $c[$br] if $l*2 < $sum;
|
||||
return if $b >= $nbranches;
|
||||
$rooted[$sum] += $c[$br];
|
||||
for my $m (reverse 1 .. $n-1) {
|
||||
next if $sum+$m > $nmax;
|
||||
tree($b, $m, $l, $sum, $c[$br]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub bicenter {
|
||||
my $s = shift;
|
||||
$unrooted[$s] += $rooted[$s/2] * ($rooted[$s/2]+1) / 2 unless $s & 1;
|
||||
}
|
||||
|
||||
for my $n (1 .. $nmax) {
|
||||
tree(0, $n, $n, 1, Math::GMPz->new(1));
|
||||
bicenter($n);
|
||||
print "$n: $unrooted[$n]\n";
|
||||
}
|
||||
63
Task/Paraffins/Pike/paraffins.pike
Normal file
63
Task/Paraffins/Pike/paraffins.pike
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
int MAX_N = 300;
|
||||
int BRANCH = 4;
|
||||
|
||||
array ra = allocate(MAX_N);
|
||||
array unrooted = allocate(MAX_N);
|
||||
|
||||
void tree(int br, int n, int l, int sum, int cnt)
|
||||
{
|
||||
int c;
|
||||
for (int b = br + 1; b < BRANCH + 1; b++)
|
||||
{
|
||||
sum += n;
|
||||
if (sum >= MAX_N)
|
||||
return;
|
||||
|
||||
// prevent unneeded long math
|
||||
if (l * 2 >= sum && b >= BRANCH)
|
||||
return;
|
||||
|
||||
if (b == br + 1)
|
||||
{
|
||||
c = ra[n] * cnt;
|
||||
}
|
||||
else
|
||||
{
|
||||
c = c * (ra[n] + (b - br - 1)) / (b - br);
|
||||
}
|
||||
|
||||
if (l * 2 < sum)
|
||||
unrooted[sum] += c;
|
||||
|
||||
if (b < BRANCH)
|
||||
{
|
||||
ra[sum] += c;
|
||||
for (int m=1; m < n; m++)
|
||||
{
|
||||
tree(b, m, l, sum, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bicenter(int s)
|
||||
{
|
||||
if (!(s & 1))
|
||||
{
|
||||
int aux = ra[s / 2];
|
||||
unrooted[s] += aux * (aux + 1) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
ra[0] = ra[1] = unrooted[0] = unrooted[1] = 1;
|
||||
|
||||
for (int n = 1; n < MAX_N; n++)
|
||||
{
|
||||
tree(0, n, n, 1, 1);
|
||||
bicenter(n);
|
||||
write("%d: %d\n", n, unrooted[n]);
|
||||
}
|
||||
}
|
||||
53
Task/Paraffins/Python/paraffins.py
Normal file
53
Task/Paraffins/Python/paraffins.py
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
try:
|
||||
import psyco
|
||||
psyco.full()
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
MAX_N = 300
|
||||
BRANCH = 4
|
||||
|
||||
ra = [0] * MAX_N
|
||||
unrooted = [0] * MAX_N
|
||||
|
||||
def tree(br, n, l, sum = 1, cnt = 1):
|
||||
global ra, unrooted, MAX_N, BRANCH
|
||||
for b in xrange(br + 1, BRANCH + 1):
|
||||
sum += n
|
||||
if sum >= MAX_N:
|
||||
return
|
||||
|
||||
# prevent unneeded long math
|
||||
if l * 2 >= sum and b >= BRANCH:
|
||||
return
|
||||
|
||||
if b == br + 1:
|
||||
c = ra[n] * cnt
|
||||
else:
|
||||
c = c * (ra[n] + (b - br - 1)) / (b - br)
|
||||
|
||||
if l * 2 < sum:
|
||||
unrooted[sum] += c
|
||||
|
||||
if b < BRANCH:
|
||||
ra[sum] += c;
|
||||
for m in range(1, n):
|
||||
tree(b, m, l, sum, c)
|
||||
|
||||
def bicenter(s):
|
||||
global ra, unrooted
|
||||
if not (s & 1):
|
||||
aux = ra[s / 2]
|
||||
unrooted[s] += aux * (aux + 1) / 2
|
||||
|
||||
|
||||
def main():
|
||||
global ra, unrooted, MAX_N
|
||||
ra[0] = ra[1] = unrooted[0] = unrooted[1] = 1
|
||||
|
||||
for n in xrange(1, MAX_N):
|
||||
tree(0, n, n)
|
||||
bicenter(n)
|
||||
print "%d: %d" % (n, unrooted[n])
|
||||
|
||||
main()
|
||||
1
Task/Paraffins/README
Normal file
1
Task/Paraffins/README
Normal file
|
|
@ -0,0 +1 @@
|
|||
Data source: http://rosettacode.org/wiki/Paraffins
|
||||
27
Task/Paraffins/REXX/paraffins.rexx
Normal file
27
Task/Paraffins/REXX/paraffins.rexx
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/*REXX program to enumerate number # paraffins for N atoms of carbon.*/
|
||||
parse arg nodes .; if nodes=='' then nodes=100 /*Not given? Use default*/
|
||||
rooted. = 0; rooted.0=1; rooted.1=1 /*define base rooted #s.*/
|
||||
unrooted. = 0; unrooted.0=1; unrooted.1=1 /* " " unrooted " */
|
||||
numeric digits max(9,nodes%2) /*may use gi-hugeic nums*/
|
||||
w=length(nodes) /*for formatted display.*/
|
||||
say right(0,w) unrooted.0 /*··· zero carbon atoms.*/
|
||||
/* [↓] process nodes. */
|
||||
do C=1 for nodes; h=C%2 /*C: # of carbon atoms.*/
|
||||
call tree 0, C, C, 1, 1 /* [↓] if C is even. */
|
||||
if C//2==0 then unrooted.C=unrooted.C + rooted.h*(rooted.h+1)%2
|
||||
say right(C,w) unrooted.C /*display formatted #'s.*/
|
||||
end /*C*/
|
||||
exit /*stick a fork in it, we're done.*/
|
||||
/*──────────────────────────────────TREE subroutine─────────────────────*/
|
||||
tree: procedure expose rooted. unrooted. nodes #. /*recursive.*/
|
||||
parse arg br,n,L,sum,cnt; nm=n-1; LL=L+L; brp=br+1
|
||||
do b=brp to 4; sum=sum+n; if sum>nodes then leave
|
||||
if b==4 then if LL>=sum then leave
|
||||
if b==brp then #.br=rooted.n*cnt
|
||||
else #.br=#.br*(rooted.n+b-brp)%(b-br)
|
||||
if LL<sum then unrooted.sum=unrooted.sum+#.br
|
||||
if b==4 then leave
|
||||
rooted.sum = rooted.sum+#.br
|
||||
do m=nm by -1 for nm; call tree b,m,L,sum,#.br; end /*m*/
|
||||
end /*b*/
|
||||
return
|
||||
36
Task/Paraffins/Racket/paraffins.rkt
Normal file
36
Task/Paraffins/Racket/paraffins.rkt
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
#lang racket
|
||||
|
||||
(define MAX_N 33)
|
||||
(define BRANCH 4)
|
||||
|
||||
(define rooted (make-vector MAX_N 0))
|
||||
(define unrooted (make-vector MAX_N 0))
|
||||
(for ([i 2]) (vector-set! rooted i 1) (vector-set! unrooted i 1))
|
||||
|
||||
(define (vector-inc! v i d) (vector-set! v i (+ d (vector-ref v i))))
|
||||
|
||||
(define (choose m k)
|
||||
(if (= k 1) m
|
||||
(for/fold ([r m]) ([i (in-range 1 k)]) (/ (* r (+ m i)) (add1 i)))))
|
||||
|
||||
(define (tree br n cnt sum l)
|
||||
(let/ec return
|
||||
(for ([b (in-range (add1 br) (add1 BRANCH))])
|
||||
(define s (+ sum (* (- b br) n)))
|
||||
(when (>= s MAX_N) (return))
|
||||
(define c (* (choose (vector-ref rooted n) (- b br)) cnt))
|
||||
(when (< (* l 2) s) (vector-inc! unrooted s c))
|
||||
(when (= b BRANCH) (return))
|
||||
(vector-inc! rooted s c)
|
||||
(for ([m (in-range (sub1 n) 0 -1)]) (tree b m c s l)))))
|
||||
|
||||
(define (bicenter s)
|
||||
(when (even? s)
|
||||
(vector-inc! unrooted s (* (vector-ref rooted (/ s 2))
|
||||
(add1 (vector-ref rooted (/ s 2)))
|
||||
1/2))))
|
||||
|
||||
(for ([n (in-range 1 MAX_N)])
|
||||
(tree 0 n 1 1 n)
|
||||
(bicenter n)
|
||||
(printf "~a: ~a\n" n (vector-ref unrooted n)))
|
||||
36
Task/Paraffins/Ruby/paraffins.rb
Normal file
36
Task/Paraffins/Ruby/paraffins.rb
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
MAX_N = 500
|
||||
BRANCH = 4
|
||||
|
||||
def tree(br, n, l=n, sum=1, cnt=1)
|
||||
for b in br+1 .. BRANCH
|
||||
sum += n
|
||||
return if sum >= MAX_N
|
||||
# prevent unneeded long math
|
||||
return if l * 2 >= sum and b >= BRANCH
|
||||
if b == br + 1
|
||||
c = $ra[n] * cnt
|
||||
else
|
||||
c = c * ($ra[n] + (b - br - 1)) / (b - br)
|
||||
end
|
||||
$unrooted[sum] += c if l * 2 < sum
|
||||
next if b >= BRANCH
|
||||
$ra[sum] += c
|
||||
(1...n).each {|m| tree(b, m, l, sum, c)}
|
||||
end
|
||||
end
|
||||
|
||||
def bicenter(s)
|
||||
return if s.odd?
|
||||
aux = $ra[s / 2]
|
||||
$unrooted[s] += aux * (aux + 1) / 2
|
||||
end
|
||||
|
||||
$ra = [0] * MAX_N
|
||||
$unrooted = [0] * MAX_N
|
||||
|
||||
$ra[0] = $ra[1] = $unrooted[0] = $unrooted[1] = 1
|
||||
for n in 1...MAX_N
|
||||
tree(0, n)
|
||||
bicenter(n)
|
||||
puts "%d: %d" % [n, $unrooted[n]]
|
||||
end
|
||||
62
Task/Paraffins/Seed7/paraffins.seed7
Normal file
62
Task/Paraffins/Seed7/paraffins.seed7
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
$ include "seed7_05.s7i";
|
||||
include "bigint.s7i";
|
||||
|
||||
const integer: max_n is 500;
|
||||
const integer: branch is 4;
|
||||
|
||||
var array bigInteger: rooted is max_n times 0_;
|
||||
var array bigInteger: unrooted is max_n times 0_;
|
||||
|
||||
const proc: tree (in integer: br, in integer: n, in integer: l, in var integer: sum, in bigInteger: cnt) is func
|
||||
local
|
||||
var integer: b is 0;
|
||||
var integer: m is 0;
|
||||
var bigInteger: c is 0_;
|
||||
var bigInteger: diff is 0_;
|
||||
begin
|
||||
for b range br + 1 to branch do
|
||||
sum +:= n;
|
||||
if sum > max_n or l * 2 >= sum and b >= branch then
|
||||
# Prevent unneeded long math.
|
||||
b := branch;
|
||||
else
|
||||
if b = (br + 1) then
|
||||
c := rooted[n] * cnt;
|
||||
else
|
||||
diff := bigInteger conv (b - br);
|
||||
c := c * (rooted[n] + pred(diff)) div diff;
|
||||
end if;
|
||||
if l * 2 < sum then
|
||||
unrooted[sum] +:= c;
|
||||
end if;
|
||||
if b < branch then
|
||||
rooted[sum] +:= c;
|
||||
for m range n-1 downto 1 do
|
||||
tree(b, m, l, sum, c);
|
||||
end for;
|
||||
end if;
|
||||
end if;
|
||||
end for;
|
||||
end func;
|
||||
|
||||
const proc: bicenter (in integer: s) is func
|
||||
begin
|
||||
if not odd(s) then
|
||||
unrooted[s] +:= (rooted[s div 2] * succ(rooted[s div 2])) >> 1;
|
||||
end if;
|
||||
end func;
|
||||
|
||||
const proc: main is func
|
||||
local
|
||||
var bigInteger: cnt is 1_;
|
||||
var integer: n is 0;
|
||||
var integer: sum is 1;
|
||||
begin
|
||||
rooted[1] := 1_;
|
||||
unrooted[1] := 1_;
|
||||
for n range 1 to max_n do
|
||||
tree(0, n, n, sum, cnt);
|
||||
bicenter(n);
|
||||
writeln(n <& ": " <& unrooted[n]);
|
||||
end for;
|
||||
end func;
|
||||
46
Task/Paraffins/Tcl/paraffins.tcl
Normal file
46
Task/Paraffins/Tcl/paraffins.tcl
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
package require Tcl 8.5
|
||||
|
||||
set maxN 200
|
||||
set rooted [lrepeat $maxN 0]
|
||||
lset rooted 0 1; lset rooted 1 1
|
||||
set unrooted $rooted
|
||||
|
||||
proc choose {m k} {
|
||||
if {$k == 1} {
|
||||
return $m
|
||||
}
|
||||
for {set r $m; set i 1} {$i < $k} {incr i} {
|
||||
set r [expr {$r * ($m+$i) / ($i+1)}]
|
||||
}
|
||||
return $r
|
||||
}
|
||||
|
||||
proc tree {br n cnt sum l} {
|
||||
global maxN rooted unrooted
|
||||
for {set b [expr {$br+1}]} {$b <= 4} {incr b} {
|
||||
set s [expr {$sum + ($b-$br) * $n}]
|
||||
if {$s >= $maxN} return
|
||||
set c [expr {[choose [lindex $rooted $n] [expr {$b-$br}]] * $cnt}]
|
||||
if {$l*2 < $s} {
|
||||
lset unrooted $s [expr {[lindex $unrooted $s] + $c}]
|
||||
}
|
||||
if {$b == 4} return
|
||||
lset rooted $s [expr {[lindex $rooted $s] + $c}]
|
||||
for {set m $n} {[incr m -1]} {} {
|
||||
tree $b $m $c $s $l
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proc bicenter {s} {
|
||||
if {$s & 1} return
|
||||
global unrooted rooted
|
||||
set r [lindex $rooted [expr {$s/2}]]
|
||||
lset unrooted $s [expr {[lindex $unrooted $s] + $r*($r+1)/2}]
|
||||
}
|
||||
|
||||
for {set n 1} {$n < $maxN} {incr n} {
|
||||
tree 0 $n 1 1 $n
|
||||
bicenter $n
|
||||
puts "${n}: [lindex $unrooted $n]"
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue