A general algorithm for arranging combinatorial problems

Source: Internet
Author: User
Tags bool first row

Although permutation and combination is a common problem in life, it is impossible to think deeply or lack of experience in program design. Because the permutation problem is always first to take the combination to arrange, and the simple arrangement problem is relatively simple, so this paper only discusses the implementation of the combinatorial problem in detail. To select the number of M (0<m<=n) in the n number as an example, the problem can be decomposed into:
1. First select the number of the largest number from the N number, and then select the number of m-1 in the remaining number of n-1, until you select 1 numbers from N (m-1).
2. Select a number from the N number, and continue with 1 steps until the maximum number of currently selectable numbers is M.
Obviously, the above method is a recursive process, that is, the recursive method can be very clean and neat to obtain all combinations.
The following is the implementation of the Recursive method:
Any combination of M elements from the array A[1..N].
A[1..N] Represents the candidate set, N is the candidate set size, n>=m>0.
B[1..M] is used to store elements in the current composition (this is where the element subscript is stored),
The constant M represents the number of elements in a combination that satisfies the condition, m=m, which are used only to output the result.
void combine (int a[], int n, int m, int b[], const int m)
{
for (int i=n; i>=m; i--)//Note the loop range here
{
B[m-1] = i-1;
if (M > 1)
Combine (a,i-1,m-1,b,m);
else//M = = 1, output a combination
{
for (int j=m-1; j>=0; j--)
cout << A[b[j]] << "";
cout << Endl;
}
}
}

Because the recursive program can be introduced into the stack, with backtracking to the corresponding non-recursive program, so the combinatorial problem can be solved by backtracking method. For the sake of understanding, we can classify the combinatorial problem into the path traversal problem of the graph, select all combinations of M number in n number, equal to in one such diagram (below with the example of selecting 3 numbers from 1,2,3,4) to get from [M,x] (m<=x<=n ) Location of all paths:
1 2 3 4
2 3 4
3 4
The above image is the first M-line of the upper-right diagonal matrix that intercepts the NXN, and if each element in the moment is considered a node in the graph, all of the combinations we require are equivalent to all the paths starting from the first column element of the first row, and to any column element in the third row, to the end of the node. And the next row of nodes must be on the right side of the previous line to connect the path, the other conditions are not connected to the path. Obviously, the sequence of numbers passed by either path corresponds to a combination that meets the requirements.
The following is an implementation of a non-recursive backtracking method:
Any combination of M elements from the array A[1..N].
A[1..N] Represents the candidate set, and M represents the number of elements in a group.
Returns the total number of all combinations.
int combine (int a[], int n, int m)
{
m = m > n? n:m;

int* order = new int[m+1];
for (int i=0; i<=m; i++)
Order[i] = i-1; Notice here that Order[0]=-1 is used as a loop to judge the identity

int count = 0;
int k = m;
BOOL flag = TRUE; Flag to find a valid combination
while (order[0] = =-1)
{
if (flag)//output meets the required combination
{
for (I=1; i<=m; i++)
cout << A[order[i]] << "";
cout << Endl;
count++;
Flag = false;
}

order[k]++; Select a new number in the current location
if (order[k] = = N)//Current position no number selectable, backtracking
{
order[k--] = 0;
Continue
}

if (K < m)//update the number at the next position in the current position
{
ORDER[++K] = order[k-1];
Continue
}

if (k = = m)
Flag = true;
}

Delete[] Order;
return count;
}

Here are the programs that test the above functions:
int main ()
{
const int N = 4;
const int M = 3;
int a[n];
for (int i=0;i<n;i++)
A[i] = i+1;

Backtracking method
cout << Combine (a,n,3) << Endl;

Recursive method
int b[m];
Combine (a,n,m,b,m);

return 0;
}

From the above analysis, the general algorithm of solving combinatorial problems is recursive and backtracking. In the case of specific problems, recursion is not a good choice for large combinatorial problems, because recursive programs are limited in the recursive layer, which can only be solved by backtracking method.

The full permutation of n numbers is relatively simple and can be implemented by ordering enumeration of the swap locations. The STL provides an algorithm next_permutation for the next permutation of a sequence, with the following algorithm principle:
1. From the end of the current sequence, look forward to two adjacent elements, so that the previous element is *i, the latter element is *ii, and satisfies *i<*ii;
2. Start the forward scan again from the end of the current sequence to find the first element greater than *i, so that *j (J may be equal to II), the I,J element is swapped;
3. Reverse the order of all elements after II (including II) so that the resulting arrangement is the next permutation of the current sequence.
The implementation code is as follows:
Template <class bidirectionaliterator>
BOOL Next_permutation (bidirectionaliterator First, Bidirectionaliterator last)
{
if (first = = last) return false; Empty range
Bidirectionaliterator i = first;
++i;
if (i = = last) return false; Only one element
i = last; I point to the tail end
I.;

for (;;)
{
Bidirectionaliterator II = i;
I.;
Above, locking a group (two) adjacent elements
if (*i < *II)//If the previous element is smaller than the last element
{
Bidirectionaliterator j = Last; Make J point to the tail end
while (!) (            *i < *--j)); Look forward from the tail until you meet a bigger element than *i.
Iter_swap (i, j); Swap I, J
Reverse (ii, last); Reverse-Rearrange all elements of II
return true;
}
if (i = = first)//go to the front
{
Reverse (first, last); All reverse Reflow
return false;
}
}
}

The following procedure demonstrates the use of next_permutation to find a sequence that is fully arranged:
int main ()
{
int ia[] = {1,2,3,4};
Vector<int> IV (IA,IA+SIZEOF (IA)/sizeof (int));

Copy (Iv.begin (), Iv.end (),ostream_iterator<int> (cout, ""));
cout << Endl;
while (Next_permutation (Iv.begin (), Iv.end ()))
{
Copy (Iv.begin (), Iv.end (),ostream_iterator<int> (cout, ""));
cout << Endl;
}

return 0;
}
Note: The initial sequence in the above program is arranged in the order of the number from small to large, if the initial sequence is unordered, the above program can only find the following parts from the current sequence, that is to say, the arrangement of Next_permutation is arranged in order from small to large.

copyright@ David 2006.5 in Beijing

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.