Decompose a permutation into cycles

15

3

There is a well-known theorem that any permutation can be decomposed into a set of cycles. Your job is to write the shortest possible program to do so.

Input:

Two lines. The first contains a number N, the second contains N distinct integers in the range [0,N-1] separated by spaces. These integers represent a permutation of N elements.

Output:

One line for each cycle in the permutation. Each line should be a space-separated list of integers in cycle order.

Cycles can be output in any order, and each cycle can be output starting at any position.

Example 1:

8
2 3 4 5 6 7 0 1

This input encodes the permutation 0->2, 1->3, 2->4, 3->5, 4->6, 5->7, 6->0, 7->1. This decomposes into cycles like this:

0 2 4 6
1 3 5 7

An equally valid output would be

5 7 1 3
2 4 6 0

Example 2:

8
0 1 3 4 5 6 7 2

valid output:

0
1
4 5 6 7 2 3

Keith Randall

Posted 2011-03-17T17:14:08.887

Reputation: 19 865

What is the point of having N in the input ? – Evpok – 2016-09-08T11:15:55.767

@Evpok: it's there in case it helps. No need to use it. – Keith Randall – 2016-09-28T20:32:22.673

@Keith What is the maximum value of N? – fR0DDY – 2011-03-17T17:34:15.367

33 chars in J :>C. – Eelvex – 2011-03-17T18:07:08.820

Let's say N<1000. – Keith Randall – 2011-03-17T18:14:32.137

Permutations are usually counted up from 1, not 0. – Dr. belisarius – 2011-03-18T16:23:38.973

6Mathematicians count from 1, computer scientists count from 0 :) – Keith Randall – 2011-03-18T23:45:27.487

@Keith I count from 42 by exponential increasing increments. – Mateen Ulhaq – 2011-03-20T04:52:31.167

Nice problem, I thought of adding this one before but never got the right opportunity.Thanks :-) – Quixotic – 2011-03-22T01:07:17.867

I now remove my 38 chars solution. – aaaaaaaaaaaa – 2011-04-07T21:55:12.263

Answers

4

C 145 134 Characters

N,A[999],i,j,f;main(){gets(&i);for(;~scanf("%d",A+N);)N++;for(;j<N;j++,f=f&&!puts(""))while(i=A[j]+1)f=printf("%d ",j),A[j]=-1,j=--i;}

http://www.ideone.com/BrWJT

fR0DDY

Posted 2011-03-17T17:14:08.887

Reputation: 4 337

Is it legal to call implicitly declared variadic functions? Is it legal to omit first int? – 6502 – 2011-03-19T23:13:03.703

It is legal to do anything as long as the code works. While it may give warnings, as long as it does not give errors, it should be Ok. – fR0DDY – 2011-03-20T03:45:08.557

The very point is in the meaning of "works". Anyway I've added an answer (139 chars) that uses this rule (i.e. where "works" means "there is at least one self-declared C compiler in which, apparently, the generated machine code works") – 6502 – 2011-03-20T08:15:08.143

+1: I like the gets(&i) idea to get rid of that useless first line, however this clearly wouldn't work on 16-bit systems if more than 10 elements are passed. But once again if the rules are "finding at least a program that claims to be a C compiler that creates an executable where in at least one case seems - at least to me - to give a valid response" then this is an improvement :-) – 6502 – 2011-03-22T07:30:21.397

2

Python 131 chars

input();d=dict((i,int(x))for i,x in enumerate(raw_input().split()))
while d:
 x=list(d)[0]
 while x in d:print x,;x=d.pop(x)
 print

the ending newline is not needed

6502

Posted 2011-03-17T17:14:08.887

Reputation: 456

1

Haskell, 131 characters

n%l|all(>n)l=(n:l>>=(++" ").show)++"\n"|1<3=""
c(_:a)=a>>=(\n->n%(takeWhile(/=n)$iterate(a!!)$a!!n))
main=interact$c.map read.words
  • Edit: (135 -> 131) >= became >, eliminated two tail calls though pattern matching & pre-application of a!!.

MtnViewMark

Posted 2011-03-17T17:14:08.887

Reputation: 4 779

1

C (sort of), 139 chars

n,j,t,a[999];main(){scanf("%*i");for(;scanf("%i",a+n)>0;)n++;while(n--)if(a[j=n]+1){for(;t=a[j]+1;a[j]=-1,j=t)printf("%i ",--t);puts("");}}

The final newline is not included.

I said "sort-of" because AFAIK for example

  1. it's not legal to omit declaration for variadic functions (ANSI C89: 3.3.2.2)
  2. int cannot be omitted for variable declaration (I didn't find where it's said it can be omitted and implicit type declaration is only described for functions. The grammar specification in the standard is basically useless as accepts much more than valid C declarations, for example double double void volatile x;)
  3. a newline at the end of a non-empty source file is mandatory (ANSI C89: A.6.2)

but the above code compiled with gcc -ocycles cycles.c apparently works anyway.

6502

Posted 2011-03-17T17:14:08.887

Reputation: 456

This is a valid C program,but this is not C99. – Quixotic – 2011-03-22T01:06:07.790

@Debanjan: No it's not ANSI C (not even 89). For example the standard says (3.3.2.2) that if a function uses a variable number of arguments then it cannot be declared implicitly at the function call site (in other words you cannot call scanf without #include <stdio.h> even if the parameters are correct and do not require conversions): <<If the function is defined with a type that includes a prototype, and the types of the arguments after promotion are not compatible with the types of the parameters, or if the prototype ends with an ellipsis ( ", ..." ), the behavior is undefined.>> – 6502 – 2011-03-22T07:17:09.133

1

J (between 2 and 32)

I'm not quite clear on i/o format, but I think C. would do, if the following output would be accepted:

   C. 0 1 3 4 5 6 7 2
┌─┬─┬───────────┐
│0│1│7 2 3 4 5 6│
└─┴─┴───────────┘

(It looks better in the J terminal.)

If it needs to be a named function that complies to my best understanding of the i/o format, that'd be 32 characters, of which 30 are for output format conversion...

g=:>@(":L:0)@(C.@".@}.~>:@i.&LF)

In action:

   g=:>@(":L:0)@(C.@".@}.~>:@i.&LF)
   g
>@(":L:0)@(C.@".@}.~ >:@i.&(10{a.))
   t
8
0 1 3 4 5 6 7 2
   g t
0          
1          
7 2 3 4 5 6

Explanation:

J is executed from right to left (practically). @ is a 'function' (not technically a function, but that's close enough) to combine functions.

  • i.&LF - find the first index of LF, a predefined variable containing ASCII character number 10, the line feed.
  • >: - find the first LF, and increment it's index by one. We don't actually want the linefeed, we want the array that follows it.
  • }.~ - Selects the part of the input that we want.
  • ". - Since the input format is valid J (*\õ/*) we can just use the eval verb (I know it's not actually called eval.) to turn it into an array
  • C. - Pure magic. I really have no idea what this does, but it seems to work!
  • ":L:0 - Representation. Turns the output of C. into a boxed sequence of strings
  • > - Unbox. The actual output is actually a string array (there are spaces behind the first to numbers of the example).

ɐɔıʇǝɥʇuʎs

Posted 2011-03-17T17:14:08.887

Reputation: 4 449

0

Clojure, 145

(let[v(vec(repeatedly(read)read))](loop[a(set v)b 0](cond(a(v b))(do(print" "b)(recur(disj a(v b))(v b)))(seq a)(do(prn)(recur a(first a)))1"")))

Somewhat ungolfed, and broken out into a function (input must be a vector, which is what (vec(repeatedly(read)read)) from above produces):

(defn p [v]
  (loop [a (set v) b 0]
    (cond
     (a (v b)) (do (print" "b) (recur (disj a (v b)) (v b)))
     (seq a) (do (prn) (recur a (first a)))
     1 "")))

(Wow, just noticed this challenge is over 3 year old. Oh well, had fun doing it anyways!)

YosemiteMark

Posted 2011-03-17T17:14:08.887

Reputation: 213