// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::os;
+use std::cmp::max;
-fn max(a: i32, b: i32) -> i32 {
- if a > b {
- a
- } else {
- b
- }
+fn fact(n: uint) -> uint {
+ range(1, n + 1).fold(1, |accu, i| accu * i)
}
-fn fannkuch_redux(n: i32) -> i32 {
- let mut perm = Vec::from_elem(n as uint, 0i32);
- let mut perm1 = Vec::from_fn(n as uint, |i| i as i32);
- let mut count = Vec::from_elem(n as uint, 0i32);
- let mut max_flips_count = 0i32;
- let mut perm_count = 0i32;
- let mut checksum = 0i32;
-
- let perm = perm.as_mut_slice();
- let perm1 = perm1.as_mut_slice();
- let count = count.as_mut_slice();
-
- let mut r = n;
- loop {
- while r != 1 {
- count[r as uint - 1] = r;
- r -= 1;
- }
-
- for (perm_i, perm1_i) in perm.mut_iter().zip(perm1.iter()) {
- *perm_i = *perm1_i;
- }
+fn fannkuch(n: uint, i: uint) -> (int, int) {
+ let mut perm = Vec::from_fn(n, |e| ((n + e - i) % n + 1) as i32);
+ let mut tperm = perm.clone();
+ let mut count = Vec::from_elem(n, 0u);
+ let mut perm_count = 0;
+ let mut checksum = 0;
- let mut flips_count: i32 = 0;
- let mut k: i32;
- loop {
- k = perm[0];
- if k == 0 {
- break;
+ for countdown in range(1, fact(n - 1) + 1).rev() {
+ for i in range(1, n) {
+ let perm0 = *perm.get(0);
+ for j in range(0, i) {
+ *perm.get_mut(j) = *perm.get(j + 1);
}
+ *perm.get_mut(i) = perm0;
- let k2 = (k+1) >> 1;
- for i in range(0i32, k2) {
- perm.swap(i as uint, (k - i) as uint);
+ let count_i = count.get_mut(i);
+ if *count_i >= i {
+ *count_i = 0;
+ } else {
+ *count_i += 1;
+ break;
}
- flips_count += 1;
}
- max_flips_count = max(max_flips_count, flips_count);
- checksum += if perm_count % 2 == 0 {
- flips_count
- } else {
- -flips_count
- };
-
- // Use incremental change to generate another permutation.
+ tperm.clone_from(&perm);
+ let mut flips_count = 0;
loop {
- if r == n {
- println!("{}", checksum);
- return max_flips_count;
- }
-
- let perm0 = perm1[0];
- let mut i: i32 = 0;
- while i < r {
- let j = i + 1;
- perm1[i as uint] = perm1[j as uint];
- i = j;
- }
- perm1[r as uint] = perm0;
-
- count[r as uint] -= 1;
- if count[r as uint] > 0 {
- break;
- }
- r += 1;
+ let k = *tperm.get(0);
+ if k == 1 { break; }
+ tperm.mut_slice_to(k as uint).reverse();
+ flips_count += 1;
}
-
- perm_count += 1;
+ perm_count = max(perm_count, flips_count);
+ checksum += if countdown & 1 == 1 {flips_count} else {-flips_count}
}
+ (checksum, perm_count)
}
fn main() {
- let args = os::args();
- let n = if args.len() > 1 {
- from_str::<i32>(args[1]).unwrap()
- } else {
- 2
- };
- println!("Pfannkuchen({}) = {}", n as int, fannkuch_redux(n) as int);
+ let n = std::os::args().get(1).and_then(|arg| from_str(*arg)).unwrap_or(2u);
+
+ let (tx, rx) = channel();
+ for i in range(0, n) {
+ let tx = tx.clone();
+ spawn(proc() tx.send(fannkuch(n, i)));
+ }
+ drop(tx);
+
+ let mut checksum = 0;
+ let mut perm = 0;
+ for (cur_cks, cur_perm) in rx.iter() {
+ checksum += cur_cks;
+ perm = max(perm, cur_perm);
+ }
+ println!("{}\nPfannkuchen({}) = {}", checksum, n, perm);
}