Boj 2848) 알고스팟어
문제
설명
먼저 들어오는 모든 알파벳을 체크하고, 연속된 문자열 간의 공통 prefix
를 구해서 바로 그 다음문자를 기준으로 대소관계를 넣었다. 이때 두 문자가 사전순이 불가능한 경우가 하나 있는데, 앞의 문자가 뒤의 문자보다 더 길면서 common prefix 가 뒤의 문자와 같은 경우이다. 이를 생각할 수 있느냐 없느냐로 문제푸는 시간이 확 달라지게 된다.
시간 복잡도
O(\(26^2\))
코드
vector<int> srcs[26];
int n_targets[26];
char matrix[26][26];
bool visits[26]; int n_alp = 0;
// 모든 문자열 종류를 기록함
inline void Regist(string& in)
{
for (auto a : in)
if (!visits[a - 'a']) {
visits[a - 'a'] = true;
n_alp++;
}
}
int main()
{
fastio;
bool contra = false;
string prev, cur;
int n; cin >> n;
cin >> cur; Regist(cur);
for (int i = 1; i < n; i++)
{
prev = cur; cin >> cur; Regist(cur);
int prefix = -1;
int min_size = min(prev.size(), cur.size());
while (prefix + 1 < min_size && prev[prefix + 1] == cur[prefix + 1]) prefix++;
// aa, a 의 경우
if (prefix == cur.size() - 1 && prev.size() > cur.size())
{
contra = true;
break;
}
if (prefix + 1 < min_size)
{
int si = prev[prefix + 1] - 'a', ei = cur[prefix + 1] - 'a';
if (matrix[si][ei] != 0 && matrix[si][ei] != '>') {
contra = true;
break;
}
matrix[si][ei] = '>';
matrix[ei][si] = '<';
}
}
if (contra) {
cout << "!";
return 0;
}
for (int i = 0; i < 26; i++)
for (int j = i + 1; j < 26; j++)
{
int w = i, l = j;
if (matrix[i][j] == 0) continue;
if (matrix[i][j] == '<') swap(w, l);
srcs[w].push_back(l);
n_targets[l]++;
}
queue<int> q;
for (int i = 0; i < 26; i++)
if (visits[i] && n_targets[i] == 0) q.push(i);
vector<int> ans; bool bAmbig = false;
while (!q.empty())
{
// 한번에 여러 갈래로 나뉘면 모호한 경우
if (q.size() > 1) {
bAmbig = true;
break;
}
int cur = q.front(); q.pop();
ans.push_back(cur);
for (int i = 0; i < 26; i++)
if (matrix[cur][i] == '>' && i != cur)
if (--n_targets[i] <= 0)
q.push(i);
}
if (bAmbig) cout << "?";
else if (ans.size() != n_alp) cout << "!";
else for (auto a : ans) cout << char(a + 'a');
}
댓글남기기