본문 바로가기
Algorithm

순열과 조합

by khyu2 2020. 10. 2.

여러 문제들을 풀면서 경우의 수를 따질 때 모든 경우의 수를 따지기 좋은 것이

바로 순열과 조합인 걸 느끼고 정리를 해보려 한다.

 

  • 중복을 포함하지 않는 순열
  • 중복을 포함한 순열
  • 중복을 포함하지 않는 조합
  • 중복을 포함한 조합

이렇게 4가지로 나눌 수 있을 것 같다.

각각의 방법에 대해서 DFS와 c++의 algorithm 헤더 파일의 next_permutation을 사용해서 만들 수 있다.

 

 

모든 순열과 조합에 대해서 n개 중에서 m개를 뽑는 경우의 수를 보자.

 

 

  • 중복을 포함하지 않는 순열(DFS)
#include <iostream>
using namespace std;
	
int ar[10], n, m;
bool vis[10];

void DFS(int cnt) {
	if (cnt == m) {
		for (int i = 0; i < m; i++) {
			cout << ar[i] << ' ';
		}
		cout << '\n';
	}
	for (int i = 1; i <= n; i++) {
		if (!vis[i]) {
			vis[i] = true;
			ar[cnt] = i;
			DFS(cnt + 1);
			vis[i] = false;
		}
	}
}

int main() {
	cin >> n >> m;
	DFS(0);

	return 0;
}

 

순열과 조합은 기본적인 틀이 있는 것 같다.

cnt == m 이 되는 경우 ar 배열에 들어있는 수들을 출력해주고 아니라면

vis 배열을 통해서 중복을 체크해준다. 중복되지 않은 수라면 DFS를 한번 더 사용해서 가지치기하는 식으로 사용해주는 틀을 벗어나지 않는다.

따라서 중복을 포함하게 해주려면

 

  • 중복을 포함한 순열
#include <iostream>
using namespace std;

int ar[10], n, m;

void DFS(int cnt) {
	if (cnt == m) {
		for (int i = 0; i < m; i++) {
			cout << ar[i] << ' ';
		}
		cout << '\n'; return;
	}
	for (int i = 1; i <= n; i++) {
		ar[cnt] = i;
		DFS(cnt + 1);
	}
}

int main() {
	cin >> n >> m;
	DFS(0);

	return 0;
}

 

그냥 vis 배열을 지워주면 방문을 처리하지 않으니 중복해서 뽑는다. 조심해야 할 점은 cnt == m 일 때 출력을 전부 하고 return;을 통해 종료를 해줘야 한다는 것이다. 종료하지 않으면 roof에 빠져서 탈출하지 못한다.

 

조합도 비슷하다.

 

  • 중복을 포함하지 않는 조합
#include <iostream>
using namespace std;

int ar[10], n, m;
bool vis[10];

void DFS(int cnt, int idx) {
	if (cnt == m) {
		for (int i = 0; i < m; i++) {
			cout << ar[i] << ' ';
		}
		cout << '\n'; 
	}
	for (int i = idx; i <= n; i++) {
		if (!vis[i]) {
			vis[i] = true;
			ar[cnt] = i;
			DFS(cnt + 1, i);
			vis[i] = false;
		}
	}
}

int main() {
	cin >> n >> m;
	DFS(0, 1);

	return 0;
}

 

순열과의 차이점은 idx인자를 넘겨주는 것이다 idx변수를 통해서 이전에 방문한 순열은 다시 보지 않게 처리할 수 있다.

예를 들어 1, 4와 4, 1은 수열에서 표시되지만 조합에서는 표시되지 않는다.

 

  • 중복을 포함한 조합
#include <iostream>
using namespace std;

int ar[10], n, m;

void DFS(int cnt, int idx) {
	if (cnt == m) {
		for (int i = 0; i < m; i++) {
			cout << ar[i] << ' ';
		}
		cout << '\n'; return;
	}
	for (int i = idx; i <= n; i++) {
		ar[cnt] = i;
		DFS(cnt + 1, i);
	}
}

int main() {
	cin >> n >> m;
	DFS(0, 1);

	return 0;
}

 

중복을 포함시키려면 마찬가지로 vis 배열만 지워주면 된다.

'Algorithm' 카테고리의 다른 글

플로이드 - 와샬 알고리즘  (0) 2020.10.19
벨만 - 포드 알고리즘  (0) 2020.10.18
유니온 파인드(Union-Find)  (0) 2020.10.15
다익스트라 알고리즘  (0) 2020.09.24
약수 구하기 최적화  (0) 2020.09.07