-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathcombination-of-multisets.cpp
137 lines (124 loc) · 2.6 KB
/
combination-of-multisets.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/**
* @file permutation-of-multisets.cpp
* @author prakash ([email protected])
* @brief
* @version 0.1
* @date 2021-08-02
*
* @copyright Copyright (c) 2021
*
*/
#include <algorithm>
#include <iostream>
#include <map>
#define NMAX 10000
using namespace std;
/**
* @brief print the permutation of unique multisets
*
* @param arr
* @param n
*/
void print_perm(int *arr, int n) {
cout << "{";
for (int i = 0; i < n; i++) {
cout << arr[i];
if (i < n - 1) {
cout << ", ";
}
}
cout << "}" << endl;
}
/**
* @brief Genrate unique combinations
* if arr of n elements has n! permutations
* then the number of unique combinations is
* n!/(n-k)!
* with length m
* @param arr
* @param c
* @param start
* @param end
* @param i
* @param n
*/
void combination_of_multisets(int *arr, int c[], int k, map<int, int> counter,
int n) {
if (k == n) {
print_perm(arr, n);
return;
}
for (auto count : counter) {
if (count.second > 0) {
arr[k] = count.first;
counter[count.first]--;
combination_of_multisets(arr, c, k + 1, counter, n);
counter[count.first]++;
}
}
}
void generate_combination(int *arr, int n) {
map<int, int> counter;
int k;
int c[NMAX];
for (int i = 0; i < n; i++) {
if (!counter[arr[i]]) {
counter[arr[i]] = 0;
}
counter[arr[i]]++;
}
combination_of_multisets(arr, c, 0, counter, n);
}
/////////////////////////////////////////////////////////////////////////
/**
* @brief cleverly finds next permutation
*
* @param arr
* @param n
* @return true
* @return false
*/
bool next_permutation(int *arr, int n) {
int i,j;
for (i = n - 2; i >= 0; i--) {
if (arr[i] < arr[i + 1]) {
break;
}
}
if (i < 0) {
reverse(arr, arr + n);
return false;
} else {
for (j = n - 1; j > i; j--) {
if (arr[j] > arr[i]) {
break;
}
}
swap(arr[i], arr[j]);
reverse(arr + i + 1, arr + n);
return true;
}
}
/**
* @brief
Besides backtracking, you may also solve it using Next Permutation: computing
the next permutation and add it to the result until it becomes the original
array
* https://stackoverflow.com/a/11425168/8336491
* @param arr
* @param n
*/
void alternate_approach(int *arr, int n) {
sort(arr, arr + n);
do {
print_perm(arr, n);
} while (next_permutation(arr, n));
}
int main(int argc, char const *argv[]) {
int arr[] = {1, 1, 2, 2};
int n = sizeof(arr) / sizeof(arr[0]);
generate_combination(arr, n);
cout << "alternate approach" << endl;
alternate_approach(arr, n);
return 0;
}