등산 수송 경제적인 스토브

다음 순열을 찾는 것입니다. 조합 공식. 배치 및 확률 이론

순열은 다음 요소들의 조합입니다. N특정 순서로 다른 요소를 취합니다. 재배열에서는 요소의 순서가 중요하며 모든 요소가 재배열에 포함되어야 합니다. N강요.

과제: 숫자 1, 2, 3의 순서에 대해 가능한 모든 순열을 찾아보세요.
다음과 같은 순열이 존재합니다:

1: 1 2 3
2: 1 3 2
3: 2 1 3
4: 2 3 1
5: 3 1 2
6: 3 2 1

반복 없는 순열

N개의 서로 다른 요소에 대한 순열 수는 다음과 같습니다. N!. 정말:

  • 둘 중 아무거나 1순위에 놓일 수 있습니다. N요소(전체 옵션 N),
  • 나머지 것 중 하나는 두 번째 위치에 배치될 수 있습니다. (N-1)요소(전체 옵션 N·(N-1)),
  • 우리가 모두를 위해 이 순서를 계속한다면 N장소에서 우리는 다음을 얻습니다: N·(N-1)·(N-2)· … ·1즉, 전체적으로 N!순열.

숫자의 모든 순열을 얻는 문제를 고려하십시오. 1…N(즉, 길이의 시퀀스 N), 여기서 각 숫자는 정확히 1번 나타납니다. 순열을 얻는 순서에는 여러 가지 옵션이 있습니다. 그러나 가장 자주 해결되는 문제는 순열을 생성하는 것입니다. 사전식주문하세요(위의 예 참조). 이 경우 모든 순열은 먼저 첫 번째 숫자로 정렬된 다음 두 번째 숫자로 정렬됩니다. 오름차순으로. 첫 번째는 순열이 될 것입니다. 1 2…N, 그리고 마지막 것 - N N-1…1.

문제를 해결하기 위한 알고리즘을 생각해 봅시다. 원래의 숫자 순서가 제공됩니다. 각 후속 순열을 얻으려면 다음 단계를 수행해야 합니다.

  • 현재 순열을 오른쪽에서 왼쪽으로 살펴보는 동시에 순열의 각 후속 요소(높은 숫자를 가진 요소)가 이전 요소(낮은 숫자를 가진 요소)보다 크지 않은지 확인해야 합니다. . 이 비율을 위반하는 즉시 정지하고 현재 숫자(위치 1)를 표시해야 합니다.
  • 이전 단계에서 표시된 것보다 큰 첫 번째 숫자에 도달할 때까지 오른쪽에서 왼쪽으로 이동한 경로를 다시 검토합니다.
  • 두 개의 결과 요소를 바꿉니다.
  • 이제 위치 1의 오른쪽에 있는 배열 부분에서 모든 숫자를 오름차순으로 정렬해야 합니다. 이전에는 이미 모두 내림차순으로 작성되었으므로 하위 시퀀스의 이 부분을 간단히 뒤집으면 됩니다.

이런 식으로 우리는 다음 단계에서 초기 시퀀스로 간주될 새로운 시퀀스를 얻게 됩니다.

C++로 구현

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

#포함하다
네임스페이스 std 사용;

{
int s = a[i];
a[i] = a[j];
a[j] = s;
}
bool NextSet(int *a, int n)
{
int j = n - 2;
while (j != -1 && a[j] >= a) j--;
if (j == -1)
거짓을 반환; // 더 이상 순열이 없습니다.
int k = n - 1;
while (a[j] >= a[k]) k--;
스왑(a, j, k);
int l = j + 1, r = n - 1;
동안 (나는 swap(a, l++, r--);
사실을 반환;
}
무효 인쇄(int *a, int n) // 순열 출력
{
정적 정수 번호 = 1; // 순열 수
cout.width(3);
시합<< num++ << ": " ;
for (int i = 0; i< n; i++)
시합<< a[i] << " " ;
시합<< endl;
}
정수 메인()
{
int n, *a;
시합<< "N = " ;
신 >> 엔;
a = 새로운 정수[n];
for (int i = 0; i< n; i++)
a[i] = i + 1;
인쇄(a, n);
while (NextSet(a, n))
인쇄(a, n);
cin.get(); cin.get();
0을 반환합니다.
}

실행 결과

반복이 있는 순열

순열 생성 문제는 특별한 주의를 기울일 가치가 있습니다. N시퀀스의 요소가 반복될 수 있는 경우의 요소입니다. 원래 시퀀스가 ​​요소로 구성되어 있다고 가정해 보겠습니다. n 1, n 2 ... n k, 여기서 요소 n 1반복된다 r 1한 번, n 2반복된다 r 2횟수 등 여기서 n 1 +n 2 +...+n 케이 =N. 모든 것을 계산해 보면 n 1 +n 2 +...+n k반복이 다른 순열 요소가 있으면 전체적으로 순열의 다양한 변형이 있습니다( n 1 +n 2 +...+n k)!. 그러나 이러한 순열 중에서 모두가 다른 것은 아닙니다. 사실 모든 것은 r 1강요 n 1우리는 서로 장소를 바꿀 수 있으며 이로 인해 순열이 변경되지는 않습니다. 같은 방법으로 요소를 재배열할 수 있습니다. n 2, 엔 3등등. 그 결과 우리는 r 1!반복 요소의 다른 배열로 동일한 순열을 작성하기 위한 옵션 n 1. 따라서 어떤 순열이라도 쓸 수 있습니다. r 1 !·r 2 !·...·r k !방법. 따라서 반복을 통한 다양한 순열의 수는 다음과 같습니다.

반복이 있는 순열을 생성하려면 위에서 설명한 반복 없이 순열을 생성하는 알고리즘을 사용할 수 있습니다. 배열 a에 반복되는 요소를 도입해 보겠습니다. 다음은 반복을 통해 순열을 생성하는 프로그램 코드입니다(main() 함수 코드만 변경됨).

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

#포함하다
네임스페이스 std 사용;
무효 스왑(int *a, int i, int j)
{
int s = a[i];
a[i] = a[j];
a[j] = s;
}
bool NextSet(int *a, int n)
{
int j = n - 2;
while (j != -1 && a[j] >= a) j--;
if (j == -1)
거짓을 반환; // 더 이상 순열이 없습니다.
int k = n - 1;
while (a[j] >= a[k]) k--;
스왑(a, j, k);
int l = j + 1, r = n - 1; // 나머지 시퀀스 정렬
동안 (나는 swap(a, l++, r--);
사실을 반환;
}
무효 인쇄(int *a, int n) // 순열 출력
{
정적 정수 번호 = 1; // 순열 수
cout.width(3); // 순열 수 출력 필드의 너비
시합<< num++ << ": " ;
for (int i = 0; i< n; i++)
시합<< a[i] << " " ;
시합<< endl;
}
정수 메인()
{
int n, *a;
시합<< "N = " ;
신 >> 엔;
a = 새로운 정수[n];
for (int i = 0; i< n; i++)
a[i] = i + 1;
a = 1; // 반복 요소
인쇄(a, n);
while (NextSet(a, n))
인쇄(a, n);
cin.get(); cin.get();
0을 반환합니다.
}

위 알고리즘의 결과는 다음과 같습니다.

순열 를 독립 순환의 곱으로 작성

순열 순서를 쉽게 찾을 수 있습니다.

.

정리 2. 주문하다
순열

(순환 하위 그룹의 순서
)같음 최소 공배수(LMK) 확장 에 포함된 독립 사이클 길이.

증거. 순열을 상상해보자
독립적인 순환의 산물로서

. (7)

사이클 이후로
독립적(서로 다른 세트에서 작동함)
), 그리고 q가 순환 하위 그룹의 차수라면,

,

,

어디
.

따라서 q는 길이와 일치하는 사이클  k 차수의 공배수입니다. .

q가 가장 작은 양수인 경우

,저것

산술의 기본 정리. 1과 같지 않은 모든 양의 정수 n은 소수의 곱으로 쓸 수 있습니다.

. (9)

이 표기법은 요인의 순서에 따라 고유합니다.

(9)에서 일치하는 소수의 곱을 거듭제곱으로 대체하면 다음을 얻습니다.

어디

소수가 많음

예.임의의 두 정수 m과 n은 동일한 소수의 곱으로 쓸 수 있습니다.


,

예. 순열 순서 결정
친절한

해결책. 순열 을 독립 순환의 곱으로 표현해 보겠습니다. 즉,

독립 사이클의 길이
동일한

결과적으로 고려중인 순열의 순서는 다음과 같습니다. 28과 같습니다.

순열을 전치의 곱으로 분해.

정의. 길이가 2인 주기를 전치라고 합니다. 모든 전치에는 다음과 같은 형식이 있습니다.
제외한 모든 문자를 그대로 둡니다.
.

정리. 모든 순열
전치의 결과로 표현될 수 있다.

증거. 순열 분해에 포함된 각 사이클  k를 전치의 곱으로 표현할 수 있다면 정리는 증명될 것입니다.
.

임의의 루프를 고려해보세요 , 예를 들어
그리고 그것을 전치의 산물로 분해해 보겠습니다.

루프 분해 알고리즘
전치의 곱으로의 변환은 그림 2에 나와 있습니다.

주기
전치

그림 2.– 사이클 분해
전치 작업으로.

루프의 각 요소 대신 모든 작업을 완료한 후 다음 요소는 로 밝혀졌고 첫 번째 요소는 마지막 위치로 이동했습니다. 그래서 사이클은 전치의 산물로 분해되는 것으로 밝혀졌습니다.

당연히 이러한 분해가 유일한 것은 아닙니다. 예를 들어

또 다른 중요한 점은 첫 번째와 두 번째 분해 모두에서 동일한 수의 전치(4)가 있다는 것입니다. 만약에
이면 전치 횟수는 다음과 같습니다.
. 비슷한 방식으로 각 사이클을 분해
순열 전치의 곱으로 우리는 전체 순열의 분해를 얻습니다 전치 작업으로.

논평. 한 주기의 전치 횟수
어쩌면 4개 이상일 수도 있어요! 예를 들어, 이 순환의 분해로부터 임의의 전치(transposition)를 취해보자:
. 그러면 그 제품
항등 순열 및 순환과 일치합니다.
형태로 표현될 수 있다

이 모든 경우에 전치 횟수가 짝수이고 4, 6, 8과 같다는 것을 쉽게 알 수 있습니다. 분해를 "연장"하는 방법이 원래 분해의 패리티를 변경하지 않는다는 것은 분명합니다.

정리. 를 다음의 순열이라고 하자. , ㅏ

. (9)

전치의 곱에서 의 분해.

그런 다음 번호

(10)

순열 의 패리티(서명 또는 부호)라고 하며 완전히 에 의해 결정됩니다. 즉, 순열 을 전치의 곱으로 분해하는 방법에 의존하지 않습니다. 게다가 만약에
, 저것

. (11)

정의. 재배치
경우에도 호출됩니다
, 그리고 이상하다면
.

순열의 패리티 정의에 따르면 모든 전치는 홀수 순열입니다.

실제로 만약에 – 조옮김, 그런 다음
, 그 다음에

결과 1. n차의 모든 짝수 순열은 부분군을 형성합니다.
주문하다
(n차 교번군이라고 합니다).

결과 2. 순열을 보자
독립적인 순환의 산물로 분해됨

,

어디
,
, …,
, …,
– 독립 사이클의 길이.

. (12)

증거. 실제로, 이전 정리에 의해 우리는

.

게다가,
왜냐면 다들 사이클은 제품으로 기록됩니다.
전치, 그 다음