Notice: The new book " Algorithm Competition " I wrote in two years has been handed over to Tsinghua University Press in February 2022 and is expected to be published in July 2022.
"Algorithm Competition" is a " compendium ", covering "basic - intermediate - advanced", about 700 pages in length. Drafts of some knowledge points have been published on this blog.
Article directory
The Blue Bridge Cup provincial competition is coming soon , here is a useful basic knowledge point.
Arrangement is a basic technique commonly used in computer programming, and every algorithm competition has topics that use arrangement.
Need to master two ways to achieve permutation ( C/C++ group ):
(1) STL's next_permutation() function. When you need to output all the full permutations, use this function directly.
(2) Self-written permutation function. If you only need to output a part of the arrangement, you cannot use the next_permutation() function at this time, and you need to write your own code.
1、next_permutation()
The function for finding the " next " full permutation in STL is next_permutation(). For example, for a sequence of three characters {a, b, c}, next_permutation() can return 6 combinations lexicographically: abc, acb, bac, bca, cab, cba.
The definition of the function next_permutation() has two forms:
bool next_permutation (BidirectionalIterator first, BidirectionalIterator last);
bool next_permutation (BidirectionalIterator first, BidirectionalIterator last, Compare comp);
Return value : If there is no next permutation combination, return false, otherwise return true. Each time next_permutation() is executed, the new arrangement will be placed in the original space.
Note the following:
(1) The range of next_permutation() permutation is [first, last) , including first and excluding last.
(2) next_permutation() starts from the current full permutation and outputs larger full permutations one by one instead of outputting all full permutations. For example, the initial sequence is {b,c,a}, which is not the smallest lexicographically, and only 3 can be output at this time.
#include <bits/stdc++.h>
using namespace std;
int main(){
string s="bca";
do{
cout<<s<<endl;
}while(next_permutation(s.begin(),s.end())); //end()指向最后一个字符的下一个位置
return 0;
}
The code can only output 3 full permutations , not 6:
bca
cab
cba
(3) If you want to get all the full permutations , you need to start with the smallest full permutation. If the initial full permutation is not the smallest, first use sort() to sort , get the smallest permutation, and then execute next_permutation(). E.g:
#include <bits/stdc++.h>
using namespace std;
int main(){
string s="bca";
sort(s.begin(),s.end()); //字符串内部排序,得到最小的排列“abc”
do{
cout<<s<<endl;
}while(next_permutation(s.begin(),s.end()));
return 0;
}
At this point, all the full permutations can be output , a total of 6:
abc
acb
bac
bca
cab
cba
(4) If there are repeated elements in the sequence, the permutation generated by next_permutation() will be deduplicated. For example "aab", the code outputs 3 permutations {aab, aba, baa}, not 6 permutations.
#include <bits/stdc++.h>
using namespace std;
int main(){
string s="aab";
sort(s.begin(),s.end()); //字符串内部排序,得到最小的排列“abc”
do{
cout<<s<<endl;
}while(next_permutation(s.begin(),s.end()));
return 0;
}
Output 3 permutations:
aab
aba
baa
There is also a full permutation function prev_permutation() in STL, which seeks the "previous" permutation combination, which is opposite to next_permutation(), that is, "from big to small".
Although next_permutation() is very convenient, it cannot print the partial permutation of m numbers out of n numbers . In some cases, it needs to be processed during the permutation process. In this case, you must write the permutation function yourself.
2. Self-written permutation function
The following is a self-written full permutation function, which can achieve partial permutation. Write a full permutation function recursively, and use b[] to record a new full permutation. When entering bfs() for the first time, b[0] selects one of n numbers, and when entering bfs() for the second time, b[1 ] pick one of the remaining n-1 numbers, ..., etc. Use vis[] to record whether a certain number has been selected. The selected number cannot be selected later.
The code can print all arrangements from small to large, provided that the numbers in a[] are from small to large, you can sort a[] first.
#include<bits/stdc++.h>
using namespace std;
int a[20] = {
1,2,3,4,5,6,7,8,9,10,11,12,13};
bool vis[20]; //记录第i个数是否用过
int b[20]; //生成的一个全排列
void dfs(int s,int t){
if(s == t) {
//递归结束,产生一个全排列
for(int i = 0; i < t; ++i)
cout << b[i] << " "; //输出一个排列
cout<<endl;
return;
}
for(int i=0;i<t;i++)
if(!vis[i]){
vis[i] = true;
b[s] = a[i];
dfs(s+1,t);
vis[i] = false;
}
}
int main(){
int n = 3;
dfs(0,n); //前n个数的全排列
return 0;
}
output:
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
If you need to print the arrangement of any m number of n numbers , for example, take the arrangement of any 3 numbers out of 4 numbers, change line 21 to n = 4, and then modify line 7 in dfs() to get the following the code:
#include<bits/stdc++.h>
using namespace std;
int a[20] = {
1,2,3,4,5,6,7,8,9,10,11,12,13};
bool vis[20]; //记录第i个数是否用过
int b[20]; //生成的一个全排列
void dfs(int s,int t){
if(s == 3) {
//递归结束,取3个数产生一个排列
for(int i = 0; i < 3; ++i) //打印4个数中3个数的排列
cout << b[i] << " ";
cout<<endl;
return;
}
for(int i=0;i<t;i++)
if(!vis[i]){
vis[i] = true;
b[s] = a[i];
dfs(s+1,t);
vis[i] = false;
}
}
int main(){
int n = 4;
dfs(0,n); //前n个数的全排列
return 0;
}
output:
1 2 3
1 2 4
1 3 2
1 3 4
1 4 2
1 4 3
2 1 3
2 1 4
2 3 1
2 3 4
2 4 1
2 4 3
3 1 2
3 1 4
3 2 1
3 2 4
3 4 1
3 4 2
4 1 2
4 1 3
4 2 1
4 2 3
4 3 1
4 3 2
3. Examples
The following is an example that requires self-written full permutation and cannot use next_permutation().
Winter vacation homework (Question 6 of C++ Group A in the 2016 Provincial Competition of the Blue Bridge Cup)
Title description: Four operations of addition, subtraction, multiplication and division:
□ + □ = □
□ - □ = □
□ × □ = □
□ ÷ □ = □
each Each square represents a number from 1 to 13, but cannot be repeated.
Q: How many options are there in total?
The title is a 13! full permutation problem. If you use next_permutation(), it is easy to write the following code:
#include <bits/stdc++.h>
using namespace std;
int a[20] = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
int main() {
int ans=0;
do{
if(a[0]+a[1]==a[2] && a[3]-a[4]==a[5] &&a[6]*a[7]==a[8] && a[11]*a[10]==a[9])
ans++;
}while(next_permutation(a,a+13));
cout<<ans<<endl;
}
Unfortunately, the above code times out seriously, because 13! = 6,227,020,800, running the code, can't end for a long, long time.
Since next_permutation() must generate a complete permutation every time, and cannot stop in the middle (only generate a part of the full permutation, for example, a permutation of 5 numbers only outputs the first 3 permutations), so in this case it is not easy to use.
Analysis of the title shows that it is not actually necessary to generate a complete arrangement. For example, if the first 3 numbers of a permutation do not satisfy "□ + □ = □", then the next 9 numbers are wrong no matter how they are arranged. This technique of terminating the search early is called "pruning", and pruning is a common optimization technique in search. The following code adds pruning to the self-written full arrangement.
#include<bits/stdc++.h>
using namespace std;
int a[20]={
1,2,3,4,5,6,7,8,9,10,11,12,13};
bool vis[20];
int b[20];
int ans=0;
void dfs(int s,int t){
if(s==12) {
if(b[9]*b[10] == b[11]) ans++;
return;
}
if(s==3 && b[0]+b[1]!=b[2]) return; //剪枝
if(s==6 && b[3]-b[4]!=b[5]) return; //剪枝
if(s==9 && b[6]*b[7]!=b[8]) return; //剪枝
for(int i=0;i<t;i++)
if(!vis[i]){
vis[i]=true;
b[s]=a[i]; //本题不用a[],改成b[s]=i+1也行
dfs(s+1,t);
vis[i]=false;
}
}
int main(){
int n=13;
dfs(0,n); //前n个数的全排列
cout<<ans;
return 0;
}
Running the code will soon output the answer:
64
4. Exercises
The following exercises for the arrangement are from the official website of the Blue Bridge Cup.
https://www.lanqiao.cn/problems/782/learning
https://www.lanqiao.cn/problems/572/learning
https://www.lanqiao.cn/problems/269/learning
https://www .lanqiao.cn/problems/208/learning