Update all new Tasks

This commit is contained in:
Ingy döt Net 2015-02-20 09:02:09 -05:00
parent 00a190b0a6
commit 91df62d461
5697 changed files with 93386 additions and 804 deletions

View 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 &nbsp; ◄── 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

View 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;
}

View 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;
}

View 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]);
}
}

View 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])
}
}

View 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]

View 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&|+<.@-:

View 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

View 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}

View 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.

View 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;

View 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";
}

View 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]);
}
}

View 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
View file

@ -0,0 +1 @@
Data source: http://rosettacode.org/wiki/Paraffins

View 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

View 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)))

View 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

View 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;

View 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]"
}