728x90
개요
문제 링크
골드 3, String, Greedy
N개의 문자열로 N/2개의 pair를 형성할 때 pair의 prefix의 최소 길이의 최댓값
접근
일단 문제의 핵심은 전체 pair들의 prefix를 생각할 필요가 없다는 것이다. Pair의 prefix의 최소 길이의 최댓값이라는 말라는 말이 엄청 헷갈릴텐데, 먼저 pair를 골라야 하고, 그 조합의 prefix 길이가 최대가 되도록한다고 천천히 생각하면 문제의 구조를 이해할 수 있다.
Pair를 고르는 것이 핵심인데, 아래 상황들을 천천히 읽어보자.
- Pair를 고를 조건, 즉 최소 prefix의 길이가 최대가 되도록 고르는 조건을 생각하는 과정이 상당히 그리디해서 Greedy를 추가했다.
- 사실 pair의 구성에는 최적의 pair가 항상 존재한다. 그게 무엇이고 어떻게 존재하냐? 하면 일단 예시를 보자.
a의 최적 pair는 b가 되고, c의 최적 pair는 d가 된다. 남아있는 문자열 중 가장 prefix의 길이가 긴 문자열을 상대 pair로 고르는 것이 이득이라는 것인데, 아래 예시를 더 보자.// ex1) a = AAAA b = AAAB c = AABB d = ABBB // answer = 1
a의 pair로 b가 아닌 c를 고른다면? c와 d의 prefix길이인 3이 방해를 받고, (a,c) = 2, (b,d) = 2로 prefix길이의 최댓값은 2가 된다.// ex2) a = AAAA b = AAAB c = AABC d = AABD // answer = 3
일단 여기까지는 예시고, 그럼 각 문자열마다 prefix의 길이가 가장 긴 문자열을 일단 고르고 봐야 한다는 건데, 이게 진짜 최적일까? 혹시 다른 선택지를 선택하면서 원래 상대가 더 최적의 선택을 할 수 있지 않나? 하는 생각을 할 수 있다.
- 다시 말해 (a,b), (c,d)의 pair가 있을 때, (a,c), (b,d)의 pair를 형성함으로써 a pair의 prefix의 길이는 줄어들지라도 (b,d)의 prefix 길이는 (c,d)보다 늘어나서 최소 prefix가 증가하지 않을까? 하는 것이다.
- 만약 a,b,c,d가 공통된 prefix를 갖지 않는 아래의 상황이라면 최소 prefix는 감소한다. 여기까지는 쉽게 생각할 수 있다.
// ex3) a = AAAA b = AAAB c = BBBB d = BBBC // answer=3
- 하지만 위에서 본 2번 예시를 다시 보자. 2번 예시는 4개 문자열의 공통 prefix가 있음에도 (a,c), (b,d) 선택에서 최소 prefix가 감소한다. 개별 최적 선택지가 b는 a, c는 d, d는 c가 되기 때문이다. 즉 pair를 형성하는 데에 겹치는 부분이 없어서 개별의 최적선택이 전체의 최적이 된다.
- 그럼 마지막으로 1번 예시를 보자. 개별 최적 선택지는 b는 a (prefix=3), c는 a,b (prefix=2), d는 a,b,c (prefix=1) 가 된다. 겹치는 부분이 생겨버렸다.
- 그럼 a에서는 어떤 문자열을 선택해야 할까? 우선 앞서 b를 선택하는 것이 최적이라 했는데, 이유는 (a,d) pair를 만들어도 기존의 (a,b), (c,d)의 최소 prefix인 1을 벗어날 수 없기 때문이다.
- c가 a또는 b의 선택을 받을 수는 없을까? 이때는 a,b 중 하나는 무조건 d를 선택해야 하는데, 이때도 어차피 최소 prefix인 1을 벗어날 수 없다.
- 만약 d pair의 prefix가 1보다 커지는 상황이라면? 그러면 d의 최적 선택지 구성이 달라질 것이고 최적 선택을 하지 않은 상황이 된다. 전제가 잘못되었다.
- 핵심은 최소 prefix를 가지는 pair를 구성하는 원소가 존재하고, 그 원소는 다른 어떤 원소와 pair를 형성해도 최소 prefix를 가진다는 것이다. 아예 첫 자리부터 다른 3번 예시, 앞의 몇 개는 같지만 결국 뒤로 가면 더 손해가 되어버리는 2번 예시, 앞이 모두 같지만 결국 그게 최소인 1번 예시를 기준으로 가닥을 잡아보면 된다.
여기까지 쭉 읽고 나면 결국 최적 선택지는 prefix의 길이가 긴 문자열이고, 인접한 문자열의 prefix의 길이가 최대가 되도록 배치하는 것은 사전순 배열이 됨을 알 수 있다. 그래서 코드 자체는 매우 단순하다. 그냥 정렬하고, 2개씩 prefix의 길이를 보면서 최솟값을 찾아주면 된다.
좀 엄밀하게 가다보니 설명을 너무 어렵게 해버렸고 틀린 부분도 좀 있는 것 같은데, 핵심은 부분의 최적이 전체의 최적이라는 것이고, 나머지는 문자열에 익숙하다면 크게 어렵지 않을 것이다.
Pseudo code
sort(string)
for (i=0;i<n;i+=2)
ans = min(prefix(s[i],s[i+1]))
Source code
#include <bits/stdc++.h>
using namespace std;
using str=string;
int pre(str &a,str &b) {
int i=0,m=a.size();
while(a[i]==b[i]&&i<m) i++;
return i;
}
int main() {
cin.tie(0);
ios::sync_with_stdio(0);
int n;
cin>>n;
str s[n];
for (auto &x:s) cin>>x;
sort(s,s+n);
int m=s[0].size();
for (int i=0;i<n;i+=2)
m=min(m,pre(s[i],s[i+1]));
cout<<m;
}
728x90
'백준브실골 > Greedy' 카테고리의 다른 글
백준 25091, Chain Reactions (0) | 2023.06.22 |
---|---|
백준 16207, 직사각형 (2) | 2023.05.10 |
백준 18513, 샘터 (0) | 2023.04.05 |
백준 14222, 배열과 연산 (0) | 2023.02.23 |
백준 1036, 36진수 (0) | 2023.02.20 |
백준 7775, 최종 순위 (0) | 2023.02.19 |
백준 2812, 크게 만들기 (0) | 2023.02.11 |
백준 1132, 합 (0) | 2023.02.11 |
댓글