NP 클래스
고친 사람 github-actions[bot]
NP 클래스는 답이 맞는지 빨리 확인할 수 있는 문제들을 한 모임으로 묶습니다. 답을 찾는 데 얼마나 걸리는지는 따지지 않습니다. 쉬운 문제와 어려운 문제가 함께 듭니다. 이 모임이 빨리 풀리는 문제의 모임과 같은지는 아직 아무도 모릅니다.
쉽고 빠른 이해
NP 클래스는 「풀기는 어려울지 몰라도 답을 받으면 맞는지 금방 확인되는 문제」의 모임입니다. 수 목록 [3, 34, 4, 12, 5, 2] 에서 몇 개를 골라 합을 9 로 만들 수 있는지 묻는 문제가 여기 듭니다. 「4 와 5」라는 답을 받으면 더해 보기만 하면 됩니다. 답 없이 찾으려면 고를 수 있는 묶음을 하나씩 따져 봐야 합니다.
이 모임이 필요한 까닭은 문제의 어려움을 견줄 기준이 있어야 하기 때문입니다. 확인은 금방 끝나지만 답을 찾는 방법은 오래 걸리는 것밖에 모르는 문제가 많습니다. 새 요구가 그런 문제와 같은 꼴이라고 알아보면 정답을 금방 내는 풀이를 찾느라 애쓰지 않고 다른 길을 고를 수 있습니다.
어떤 문제가 이 모임에 드는지는 이렇게 가립니다.
- 답이 「예」나 「아니요」인 문제로 바꿔 묻습니다
- 답이 「예」일 때 그 근거로 내밀 것을 정합니다
- 그 근거를 빨리 확인하는 방법이 있으면 이 모임에 듭니다
백엔드에서는 회의 시간표 짜기나 서버에 작업 나눠 싣기 같은 요구에서 이 이름을 만납니다. 큰 입력에서는 정답 대신 쓸 만한 답을 빨리 내는 방법을 고릅니다. 그렇게 받은 답이 조건을 지키는지는 금방 확인할 수 있습니다.
이 이름은 오해를 부르기 쉽습니다. 이 모임에 든다고 어려운 문제가 되는 것이 아닙니다. 빨리 푸는 방법이 없다는 증명도 아닙니다.
상세
네 자리 번호 자물쇠가 있다고 합시다. 번호를 모르면 0000 부터 하나씩 돌려 봐야 합니다. 누가 번호를 알려 주면 한 번 맞춰 보고 열리는지만 보면 됩니다. 찾는 일과 확인하는 일의 수고가 이렇게 다릅니다.
NP(Nondeterministic Polynomial time, 비결정적 다항 시간) 클래스는 이 차이를 문제의 모임으로 옮긴 이름입니다. 여기서 클래스는 프로그래밍의 클래스가 아니라 문제를 한데 모은 모임을 뜻합니다. 「비결정적」이라는 이름의 뜻은 뒤 소절에서 풉니다.
이 절은 정의에 드는 낱말 셋을 먼저 풉니다. 결정 문제, 다항 시간, 근거와 검증기입니다. 그다음 정의를 세우고 부분집합 합 문제로 확인 과정을 직접 봅니다. 끝으로 이웃한 모임과의 관계, 백엔드에서 이 이름을 만나는 곳, 흔한 오해를 차례로 봅니다.
결정 문제
결정 문제는 답이 「예」나 「아니요」인 문제입니다. 「이 목록에 7 이 있나」가 결정 문제입니다. NP 클래스에는 결정 문제만 듭니다. 답의 꼴을 하나로 맞춰 두어야 서로 다른 문제끼리 어려움을 견줄 수 있기 때문입니다.
「가장 짧은 경로를 구하라」처럼 가장 작거나 큰 값을 구하는 문제는 최적화 문제라고 부릅니다. 이런 문제도 「길이 k 이하인 경로가 있나」로 바꿔 물으면 결정 문제가 됩니다. 이렇게 바꾼 물음을 그 문제의 결정판이라고 부릅니다.
다항 시간
다항 시간은 입력 크기 n 에 대해 n², n³ 처럼 n 을 정해진 횟수만큼 곱한 값을 넘지 않는 시간입니다. 입력이 두 배가 되어도 시간은 정해진 배수로만 늡니다. 그래서 다항 시간은 컴퓨터로 감당할 수 있는 일의 경계로 흔히 쓰입니다.
반대편에는 지수 시간이 있습니다. 2ⁿ 처럼 n 이 하나 늘 때마다 시간이 두 배가 됩니다. n 이 20 과 60 일 때 두 쪽의 일의 양을 견주면 이렇습니다.
20 ** 3 # 8000
60 ** 3 # 216000
2 ** 20 # 약 100만
2 ** 60 # 약 115경
n 이 20 에서 60 으로 세 배가 되면 n³ 은 27 배가 됩니다. 2ⁿ 은 1조 배쯤 커집니다. NP 클래스의 정의에서 「빨리」는 언제나 다항 시간을 뜻합니다.
근거와 검증기
근거는 답이 「예」라는 것을 보여 주는 증거물입니다. 「합을 9 로 만들 수 있나」에서는 고른 수 묶음이 근거입니다. 근거가 있으면 「예」라는 주장을 말로 믿을 필요 없이 직접 따져 볼 수 있습니다.
검증기는 입력과 근거를 함께 받아 그 근거가 맞는지 판정하는 프로그램입니다. 판정은 「맞다」나 「아니다」 둘 중 하나입니다. 검증기는 근거를 찾지 않습니다. 받은 근거를 따져 보기만 합니다.
NP 클래스의 정의
NP 클래스는 결정 문제의 모임입니다. 결정 문제 X 가 아래 세 조건을 채우는 검증기를 가지면 X 는 NP 에 듭니다.
- 검증기가 다항 시간 안에 판정을 끝냅니다
- 답이 「예」인 입력에는 검증기가 「맞다」고 하는 근거가 하나 이상 있습니다
- 답이 「아니요」인 입력에는 검증기가 「맞다」고 하는 근거가 하나도 없습니다
근거의 길이에도 한도가 있습니다. n², n³ 처럼 입력 크기로 정해진 길이를 넘으면 안 됩니다. 조건 1 이 검증기가 일하는 시간을 묶는다면 이 한도는 내미는 근거의 크기를 묶습니다. 근거가 지나치게 길면 받아 읽기만 해도 다항 시간을 넘기기 때문입니다.
이 정의는 답을 찾는 방법을 하나도 묻지 않습니다. 근거가 어디서 왔는지도 묻지 않습니다. 확인이 다항 시간에 끝난다는 것 하나만 요구합니다.
부분집합 합 문제로 보는 확인
부분집합 합 문제는 수 목록에서 몇 개를 골라 합을 목표값으로 만들 수 있는지 묻습니다. 목록이 [3, 34, 4, 12, 5, 2] 이고 목표값이 9 라고 합시다. 근거는 고른 수 묶음입니다. 검증기는 이렇게 짭니다.
def verify(nums, target, pick):
ok = all(pick.count(x) <= nums.count(x)
for x in pick)
return ok and sum(pick) == target
nums = [3, 34, 4, 12, 5, 2]
verify(nums, 9, [4, 5]) # True
verify(nums, 9, [3, 4]) # False
verify(nums, 9, [4, 4, 1]) # False
검증기는 두 가지만 봅니다. 고른 수가 목록 안에 있는지, 그 합이 목표값과 같은지입니다. 근거의 수마다 근거와 목록을 한 번씩 훑어도 일의 양은 길이의 제곱 정도라서 다항 시간입니다. 마지막 줄은 목록에 하나뿐인 4 를 두 번 쓰고 없는 1 을 넣어서 거절됩니다.
근거 없이 답을 찾는 일은 사정이 다릅니다. 원소가 n 개면 고를 수 있는 묶음이 2ⁿ 개입니다. 이 문제를 다항 시간에 푸는 방법은 아직 알려지지 않았습니다.
아래 그림은 목록에서 3, 4, 5 세 수만 골라 갈림길을 그린 것입니다. 갈림길마다 「이 수를 넣나 빼나」를 정하므로 갈래가 한 층마다 두 배로 늡니다.
flowchart TD
R["3 을 넣나"]
R -->|넣는다| A1["4 를 넣나"]
R -->|뺀다| A2["4 를 넣나"]
A1 -->|넣는다| B1["5 를 넣나"]
A1 -->|뺀다| B2["5 를 넣나"]
A2 -->|넣는다| B3["5 를 넣나"]
A2 -->|뺀다| B4["5 를 넣나"]
B1 -->|넣는다| L1["3·4·5<br>합 12"]
B1 -->|뺀다| L2["3·4<br>합 7"]
B2 -->|넣는다| L3["3·5<br>합 8"]
B2 -->|뺀다| L4["3<br>합 3"]
B3 -->|넣는다| L5["4·5<br>합 9"]
B3 -->|뺀다| L6["4<br>합 4"]
B4 -->|넣는다| L7["5<br>합 5"]
B4 -->|뺀다| L8["없음<br>합 0"]
L5 ~~~ N["34 · 12 · 2 도 같은 식으로 갈린다 · 모두 64갈래<br>「예」는 굵은 길 하나로 보인다<br>「아니요」는 64갈래 끝을 전부 봐야 한다"]
class R,A2,B3,L5 hit
classDef hit stroke-width:3px
linkStyle 1,4,10 stroke-width:3px
굵게 그린 길은 3 을 빼고 4 와 5 를 넣은 기록입니다. 갈림길마다 고른 쪽을 이어 적은 이 기록이 곧 근거 [4, 5] 입니다.
확인은 다항 시간에 끝나도 지금 아는 방법으로는 찾는 데 지수 시간이 드는 문제입니다. NP 클래스가 붙잡으려는 문제의 전형이 이렇습니다.
「예」와 「아니요」의 비대칭
정의는 「예」인 경우의 근거만 요구합니다. 「아니요」를 빨리 확인하라는 요구는 없습니다. 그래서 「아니요」를 빨리 확인할 길이 없는 문제도 NP 에 들 수 있습니다.
부분집합 합에서 답이 「아니요」라면 「합을 맞추는 묶음이 없다」를 보이려고 무엇을 내밀어야 할까요. 짧게 확인되는 근거는 알려져 있지 않습니다. 위 그림으로 치면 굵은 길 하나가 아니라 갈래 끝을 전부 보여야 합니다.
「아니요」를 빨리 확인할 수 있는 결정 문제의 모임은 따로 co-NP라고 부릅니다. NP 와 co-NP 가 같은 모임인지도 아직 밝혀지지 않았습니다.
이름 속의 비결정적 기계
비결정적 튜링 기계는 갈림길을 만나면 맞는 쪽을 알아서 골라 가는 가상의 계산 기계입니다. 실제로 만들 수 있는 기계가 아닙니다. 어려움을 견주려고 세운 이론 속 기계입니다. NP 는 원래 이 기계가 다항 시간에 푸는 결정 문제의 모임으로 정의됐습니다.
이 정의는 검증기 정의와 같은 모임을 가리킵니다. 앞의 부분집합 합 그림에서 갈림길은 「이 수를 넣나 빼나」였습니다. 기계가 갈림길마다 고른 길을 적어 두면 그 기록이 근거가 됩니다. 근거가 있으면 기계는 갈림길마다 근거가 가리키는 쪽을 고르면 됩니다.
P 와 NP
P(Polynomial time, 다항 시간)는 다항 시간 안에 푸는 방법이 있는 결정 문제의 모임입니다. 「정렬된 목록에 값 x 가 있나」는 반씩 나눠 찾으면 금방 답이 나오므로 P 에 듭니다.
P 의 문제는 모두 NP 에도 듭니다. 근거를 받을 필요도 없이 처음부터 풀어 버리면 확인이 끝나기 때문입니다. 검증기가 근거를 무시하고 문제를 직접 풀면 됩니다.
NP 의 문제가 모두 P 에 드는지는 아무도 증명하지 못했습니다. 「다항 시간에 확인되는 문제는 다항 시간에 찾을 수도 있나」라는 이 물음이 P 대 NP 문제입니다. 연구자 대부분은 두 모임이 다르다고 봅니다.
NP-완전과 NP-난해
NP 안의 문제끼리 어려움을 견주려면 한 문제를 다른 문제로 바꿔 푸는 방법이 있어야 합니다. 이 소절은 그 방법을 먼저 풀고 그 위에서 NP-완전과 NP-난해를 차례로 정합니다.
환원은 문제 X 의 입력을 문제 C 의 입력으로 바꾼 뒤 C 를 풀어 X 의 답을 얻는 일입니다. C 의 답 「예·아니요」를 X 의 답으로 그대로 씁니다. 여기서는 바꾸는 일도 다항 시간에 끝나야 합니다. 바꾸는 데 오래 걸리면 C 가 빨리 풀려도 X 는 빨리 풀리지 않기 때문입니다.
NP-완전은 NP 안에 들면서 NP 의 모든 문제가 자기에게 환원되는 문제입니다. NP 안에서 가장 어려운 문제들이라고 풀어 말합니다. 앞에서 본 부분집합 합 문제가 NP-완전입니다.
NP-완전 문제 하나만 다항 시간에 풀려도 NP 전체가 다항 시간에 풀립니다. 아래 그림의 순서를 따라가면 그 까닭이 보입니다. 바꾸는 데 다항 시간, C 를 푸는 데 다항 시간이면 둘을 이어도 다항 시간입니다.
flowchart TD
X["NP 의 아무 문제 X 의 입력"] --> T["다항 시간에 바꾼다"]
T --> CI["NP-완전 문제 C 의 입력"]
CI --> S["C 를 푼다"]
S --> A["예 · 아니요<br>X 의 답으로 그대로 쓴다"]
S -.->|"C 가 다항 시간에 풀리면"| F["X 도 다항 시간에 풀린다"]
NP-난해 문제는 NP 의 모든 문제가 자기에게 환원되기만 하면 됩니다. NP-완전과 달리 NP 에 드는지는 따지지 않습니다. 그래서 NP-난해 문제는 NP 밖에 있을 수도 있습니다. NP-완전 문제는 NP-난해이면서 NP 에도 드는 문제입니다.
외판원 순회는 모든 도시를 한 번씩 도는 가장 짧은 순회를 찾는 문제입니다. 원래 물음은 순회 자체를 내놓으라고 하는 최적화 문제라서 답이 「예·아니요」가 아닙니다. 최적화 문제로 물은 이 원래 판을 최적화판이라고 부릅니다. 최적화판은 NP 에 넣을 수 없지만 NP-난해에 듭니다.
「길이 k 이하인 순회가 있나」로 바꾼 결정판은 NP 에 듭니다. 이 결정판은 NP-완전이기도 합니다.
P 와 NP 가 다르다고 믿을 때 NP 안을 그리면 아래와 같습니다. 바깥 상자가 NP 입니다. P 와 NP-완전은 그 안에서 서로 겹치지 않습니다.
flowchart TD
subgraph NP["NP · 답을 빨리 확인할 수 있는 결정 문제"]
P["P · 빨리 풀리는 결정 문제<br>정렬된 목록에서 값 찾기"]
C["NP-완전 · NP 안에서 가장 어려운 문제<br>부분집합 합 문제 · 외판원 순회 결정판"]
end
백엔드에서 만나는 NP 문제
회의 시간표 짜기, 서로 충돌하는 옵션을 피해 설정 고르기, 서버마다 용량 안에서 작업 나눠 싣기가 NP 의 문제입니다. 셋은 차례로 그래프 색칠, SAT(Boolean satisfiability, 불리언 만족 가능성 문제), 빈 패킹이라는 이름으로 알려져 있습니다. 셋 다 결정판으로 바꿔 물으면 근거를 받았을 때 확인이 금방 끝납니다. 셋 다 큰 입력에서 정답을 빨리 찾는 방법은 알려져 있지 않습니다.
그래서 큰 입력에서는 정답을 고집하지 않습니다. 근사 알고리즘이나 휴리스틱으로 쓸 만한 답을 빨리 내는 쪽을 고릅니다.
다항 시간에 확인된다는 성질은 여기서 쓸모가 있습니다. 외부 풀이 프로그램이나 휴리스틱이 내놓은 답이 조건을 지키는지는 다항 시간에 따져 볼 수 있습니다. 답을 만든 쪽을 믿지 않아도 검증기 하나로 걸러 낼 수 있습니다.
큰 수를 소수의 곱으로 나누는 소인수분해도 확인이 쉬운 문제입니다. 결정판은 「이 수에 1 보다 크고 k 보다 작은 인수가 있나」를 묻습니다. 그 인수를 근거로 받으면 나눠 보기만 하면 확인이 끝납니다. 그래서 결정판이 NP 에 듭니다.
공개 키 암호의 일부 방식은 이 확인과 찾기의 차이로 안전성을 얻습니다. 인수를 받으면 확인은 금방 끝납니다. 큰 수에서 인수를 찾는 일은 지금 아는 방법으로는 다항 시간에 끝나지 않습니다. P 와 NP 가 같다고 밝혀지면 이론상 소인수분해도 다항 시간에 풀립니다.
흔한 오해
NP 라는 이름은 자주 잘못 읽힙니다. 아래는 그 오해와 바른 읽기입니다.
| 오해 | 바른 읽기 |
|---|---|
| NP 는 「다항 시간이 아님(Not Polynomial)」의 줄임이다 | N 은 「비결정적(Nondeterministic)」이다. 다항 시간에 확인된다는 뜻에 가깝다 |
| NP 에 든 문제는 어렵다 | P 의 쉬운 문제도 모두 NP 에 든다. 어려운 쪽은 NP-완전이다 |
| NP 문제는 풀 수 없다 | 가능한 근거를 모두 만들어 하나씩 확인하면 지수 시간에 반드시 풀린다 |
| NP-난해와 NP 는 같은 말이다 | NP-난해는 NP 에 안 드는 문제도 품는다. 외판원 순회 최적화판이 그렇다 |
| NP 에 든다고 하면 얼마나 오래 걸릴지 알 수 있다 | 다항 시간에 확인된다는 것만 말한다. 푸는 데 걸리는 시간은 알고리즘마다 따로 따져야 한다 |
셋째 줄은 NP 의 문제가 모두 풀리는 문제라는 뜻입니다. 어떤 알고리즘으로도 못 푸는 정지 문제와는 다른 종류의 어려움입니다. NP 에서 따지는 것은 풀리느냐가 아니라 얼마나 빨리 풀리느냐입니다.
관련 항목
NP 클래스가 속하는 상위 분류
복잡도 클래스 · 계산 복잡도 이론 · 계산 이론 · 알고리즘 분석 · 알고리즘
NP 클래스를 정의하는 데 쓰이는 개념
결정 문제 · 최적화 문제 · 다항 시간 · 지수 시간 · 검증기 · 튜링 기계 · 비결정적 튜링 기계 · 시간 복잡도 · 빅오 표기법
NP 클래스와 포함 관계로 엮이는 복잡도 클래스
P 클래스 · co-NP · NP-완전 · NP-난해 · NP-중간 · PSPACE · EXPTIME · BPP
NP 클래스를 둘러싼 정리와 미해결 문제
P 대 NP 문제 · 환원 · 다항 시간 환원 · 쿡-레빈 정리 · 래드너 정리 · 정지 문제
NP 클래스에 드는 대표 결정 문제
부분집합 합 문제 · SAT · 3-SAT · 그래프 색칠 · 해밀턴 순환 · 외판원 순회 · 배낭 문제 · 소인수분해 · 그래프 동형 문제
NP 클래스의 문제 앞에서 고르는 풀이 방법
완전 탐색 · 백트래킹 · 동적 계획법 · SAT 풀이기 · 근사 알고리즘 · 휴리스틱 · 정수 선형 계획법
NP 클래스의 성질에 기대는 응용
공개 키 암호 · RSA · 일방향 함수 · 영지식 증명
다른 이름: NP · NP class · Nondeterministic Polynomial time · 비결정적 다항 시간 · 클래스 NP