Permutation
Programs that solve logic puzzles, such as Sudoku, use many permutations and combinations.
Permutations and combinations can be found in libraries on the internet,
but one important function is required.
For example, suppose you want to select 5 out of 6 ('1,2,3,4,5') to produce (6P5).
When using this to evaluate a group of events, if the second event turns out to be wrong,
the evaluation of the third and subsequent events is meaningless and stops.
The next permutation ("1,2,3,4,6") and the one after that ("1,2,3,5,4") are meaningless.
It makes sense to skip these and move on to the permutations ("1, 3, 2, 4, 5").
In this way, when generating permutations one after another,
we need the ability to specify and skip permutation positions.
In GNPX, the following classes handle permutations:
The code that actually generates the permutations is shown below.
public class Permutation{
private int N=0;
private int R=0;
private int[] Pwrk=null;
public int[] Pnum=null;
private bool First;
public Permutation( int N, int R=-1 ){
this.N=N;
this.R=R;
if( R<=0 || R>N ) this.R=N;
if( N>0 ){
Pwrk = Enumerable.Range(0,N).ToArray();
Pnum = Enumerable.Range(0,this.R).ToArray();
}
First=true;//(The first permutation has already been created in the constructor)
}
public bool Successor( int skip=-1 ){
if( First || Pwrk==null ){ First=false; return (Pwrk!=null); }
int r = (skip>=0)? skip: R-1;
if( r>N-1 ) r=N-1;
do{
if( r<0 ) break;
int A=Pwrk[r];
L_1:
if( A>=N-1 ){ r--; continue; }
A++;
for( int k=0; k<r; k++ ){ if( Pwrk[k]==A ) goto L_1; }
Pwrk[r]=A; //The next update position (r) and the number (A)
if( r<N-1 ){
int[] wx = Enumerable.Range(0,N).ToArray();
for( int k=0; k<=r; k++ ) wx[Pwrk[k]]=-1;//Exclude used digits
int n=0;
for( int k=r+1; k<N; k++ ){ // Fill the number after the change position
for( ; n<N; n++ ){
if( wx[n]<0 ) continue;
Pwrk[k]=wx[n++];
break;
}
}
}
for( int k=0; k<R; ++k ) Pnum[k]=Pwrk[k];//(Copy to external reference array)
return true;
}while(true);
return false;
}
public override string ToString(){
string st=""; Array.ForEach( Pnum, p=> st+=(" "+p) );
st += " "; Array.ForEach( Pwrk, p=> st+=(" "+p) );
return st;
}
}
Use Permutation like this:
Each time you call Successor, it generates the next permutation,
and the return value is true while generating it, and false when it reaches the end.
Specifies the change position for the next permutation generation to skip wasteful generation.
The change position can be changed dynamically. The position specification is from 0 (permutation size - 1),
and in other cases or when the specification is omitted, the skip function will not work.
var perm = new Permutation(6,5);
int skip=4;
while(perm.Successor(skip) ){
(Evaluation process) (Set change position skip for next permutation generation)
}*test code
class Program{
static void Main( string[ ] args ) {
Console.WriteLine( "* Permutation(4) *\n Successor()" );
Permutation perm = new Permutation(4);
while(perm.Successor()) Console.WriteLine( perm );
Console.WriteLine( "\n* Permutation(4,2) *\n Successor()" );
perm = new Permutation(4,2);
while(perm.Successor()) Console.WriteLine( perm );
Console.WriteLine( "\n* Permutation(4,3) *\n Successor(1)" );
perm = new Permutation(4,3);
while(perm.Successor(1)) Console.WriteLine( perm );
Console.Write( "\nExit with key input;" );
Console.ReadKey();
}
}Execution results
(left: permutation generation results, right: working data inside the function)
* Permutation(4) *
0 1 2 3 0 1 2 3
0 1 3 2 0 1 3 2
0 2 1 3 0 2 1 3
0 2 3 1 0 2 3 1
0 3 1 2 0 3 1 2
0 3 2 1 0 3 2 1
1 0 2 3 1 0 2 3
1 0 3 2 1 0 3 2
1 2 0 3 1 2 0 3
1 2 3 0 1 2 3 0
1 3 0 2 1 3 0 2
1 3 2 0 1 3 2 0
2 0 1 3 2 0 1 3
2 0 3 1 2 0 3 1
2 1 0 3 2 1 0 3
2 1 3 0 2 1 3 0
2 3 0 1 2 3 0 1
2 3 1 0 2 3 1 0
3 0 1 2 3 0 1 2
3 0 2 1 3 0 2 1
3 1 0 2 3 1 0 2
3 1 2 0 3 1 2 0
3 2 0 1 3 2 0 1
3 2 1 0 3 2 1 0
* Permutation(4,2) *
0 1 0 1 2 3
0 2 0 2 1 3
0 3 0 3 1 2
1 0 1 0 2 3
1 2 1 2 0 3
1 3 1 3 0 2
2 0 2 0 1 3
2 1 2 1 0 3
2 3 2 3 0 1
3 0 3 0 1 2
3 1 3 1 0 2
3 2 3 2 0 1
* Permutation(4,3) *
0 1 2 0 1 2 3
0 2 1 0 2 1 3
0 3 1 0 3 1 2
1 0 2 1 0 2 3
1 2 0 1 2 0 3
1 3 0 1 3 0 2
2 0 1 2 0 1 3
2 1 0 2 1 0 3
2 3 0 2 3 0 1
3 0 1 3 0 1 2
3 1 0 3 1 0 2
3 2 0 3 2 0 1