728x90
개요
문제 링크
골드 1, Graph
m개 쌍의 전후관계가 바뀔 때 다른 쌍의 전후관계를 유지하며 변경 가능한지 출력하기
접근
- 그래프의 개념이나 수학적 센스를 기르기 매우 좋은 문제. 우선 출력조건을 잘 보면 순위를 찾을 수 없는 경우 "?"를 출력하라고 나와있는데, 순위를 찾을 수 없는 경우는 존재하지 않는다.
- 왜인지가 쉽게 생각되지 않는 이유는 "데이터에 일관성이 없다" 라는 말이 전혀 이해가 안되기 때문인데, 세 번째 테케를 이해하는 것부터 해보자.
- [1 2 3 4]에서 1,2 앞뒤가 바뀌고, 2,3, 3,4 바뀌면 엥 [4 3 2 1]이면 되는거 아님? 하고 생각할 수 있다. 하지만 핵심은 저 세 가지 바뀌는 관계 외에, 원래 존재하던 나머지 세 개 (1,3 / 1,4 / 2,4)의 전후관계가 유지되어야 한다는 것이다.
- [4 3 2 1]로 배치하면 1,3 / 1,4 / 2,4 의 전후관계가 모두 바뀌어버리기 때문에 [4 3 2 1]로 만들고 싶었다면 m=6이고 1,2부터 3,4까지 6개 쌍이 모두 들어갔어야 한다.
- 자 그럼 문제로 다시 돌아와 "?"가 존재할 수 없는 이유에 대해 생각해보자. m개의 쌍의 순서에 변화를 줄 때, 나머지 쌍들의 관계를 해치지 않으면서 순서를 재배치하는 경우는 딱 하나만 존재하거나 존재하지 않는다. 존재한다고 가정하고 생각을 해보면 모순이 생기니 당연한 것이다.
- 그럼 "?"는 출력하지 않아도 되는 것을 알겠고, 이제 안되는 경우를 생각해보자.
- 만약 [1 2 3]의 배치에서 3이 1보다 앞에 있도록 재배치한다고 생각해보자.
앞과 뒤를 이어서 원순열을 만든다? 4차원 공간이라면 가능하지 않을까...// 바꾸려는 관계 (1,3) --> (3,1) // 기존의 관계 (1,2), (2,3)
- 결론은 3>1, 1>2, 2>3인 상황을 만들 수는 없다. 그런데 이거 어디서 많이 본 것 아닌가? 바로 사이클이다.
- 만약 [1 2 3]의 배치에서 3이 1보다 앞에 있도록 재배치한다고 생각해보자.
- 그래서 모든 전후 관계에 변화를 주었을 때 사이클이 존재한다면 IMPOSSIBLE이다. 이제 구현을 하면서 시간을 줄여보자.
- 먼저 인접리스트로 풀어보자. 기존의 관계를 추가하는 방법은? i<j에 대해 adj[a[i]].push(a[j]) 를 해주면 된다. adj[i]는 i보다 뒤에 있는 원소의 모음이 되겠다.
// set 사용 for (int j=0;j<n;j++) for (int i=0;i<j;i++) adj[a[i]].insert(a[j]);
- 그런 다음 m번 인접리스트를 수정한다. a,b를 받아올 것인데, 만약에 b뒤에 a가 있다면? swap을 해주면 된다.
그리고 DFS로 n개의 cycle을 찾아주면?while(m--) { int a,b; cin>>a>>b; if (adj[b].count(a)) swap(a,b); // b뒤에 a adj[a].erase(b); adj[b].insert(a); }
시원하게 시간초과다. 여기까지가 쉽게 할만한 생각이라 소개해봤다.bool dfs(adj,n,vis) { if (vis[n]) return 0; vis[n]=1; for (x:adj[n]) if (!dfs(adj,x,vis)) return 0; vis[x]=0; return 1; }
- 사실은 인접리스트를 사용하지 않아도 되는데, 우리가 궁금한 것은 a뒤에 무엇이 있는지가 아니라 몇개나 있는지에 대한 것이기 때문이다.
- 그래서 count 배열을 써보자. m번 배열을 수정하기 위해서는 a의 count는 하나 줄이고, b의 count는 하나 늘려주면 된다. a와 b의 swap조건은? a가 b의 뒤에 있을 때이다. 즉 b의 index가 더 작을 때.
while(m--) { int a,b; cin>>a>>b; if (ind[b]<ind[a]) swap(a,b); cnt[b]++,cnt[a]--; }
- 그런 다음 사이클이 존재하는 조건이자, 유효하지 않을 조건은? count가 중복되는 경우이다. 자신보다 뒤에 오는 원소의 개수가 정확히 맨 뒤부터 0...n-1의 배열을 이루기 때문이다.
for (int i=1;i<=n;i++) { if (s[cnt[i]]) { cout<<"IMPOSSIBLE\n"; return; } s[cnt[i]]=i; }
- 그럼 배열을 어떻게 변형해야 하는지도 쉽게 생각할 수 있다. 뒤에 k개의 원소가 있는 수를 뒤에서 k번째에 위치하도록 만들어주면 된다.
- 먼저 인접리스트로 풀어보자. 기존의 관계를 추가하는 방법은? i<j에 대해 adj[a[i]].push(a[j]) 를 해주면 된다. adj[i]는 i보다 뒤에 있는 원소의 모음이 되겠다.
Source code
// 2020KB, 12ms
#include <bits/stdc++.h>
using namespace std;
using vec=vector<int>;
void test() {
int n;cin>>n;
vec a(n),ind(n+1),cnt(n+1);
for (int i=0;i<n;i++) {
cin>>a[i],ind[a[i]]=i;
cnt[a[i]]=n-i-1;
}
int m;cin>>m;
while(m--) {
int a,b;
cin>>a>>b;
if (ind[b]<ind[a]) swap(a,b);
cnt[b]++,cnt[a]--;
}
vec s(n,0);
for (int i=1;i<=n;i++) {
if (s[cnt[i]]) {
cout<<"IMPOSSIBLE\n";
return;
}
s[cnt[i]]=i;
}
for (int i=n-1;i>=0;i--)
cout<<s[i]<<" ";
cout<<"\n";
}
int main() {
cin.tie(0);ios::sync_with_stdio(0);
int t;cin>>t;
while(t--)test();
}
// 1124KB, 16ms
#include <stdio.h>
#define N 510
int a[N],ind[N],cnt[N],s[N];
void test() {
int n;
scanf("%d",&n);
for (int i=0;i<n;i++) {
scanf("%d",a+i);
ind[a[i]]=i,cnt[a[i]]=n-i-1;
s[i]=0;
}
int m;
scanf("%d",&m);
while(m--) {
int a,b,t;
scanf("%d%d",&a,&b);
if (ind[b]<ind[a])
t=b,b=a,a=t;
cnt[b]++,cnt[a]--;
}
for (int i=1;i<=n;i++) {
if (s[cnt[i]]) {
printf("IMPOSSIBLE\n");
return;
}
s[cnt[i]]=i;
}
for (int i=n-1;i>=0;i--)
printf("%d ",s[i]);
printf("\n");
}
int main() {
int t; scanf("%d",&t);
while(t--) test();
}
# 31256KB, 148ms
import sys;input=sys.stdin.readline
def inp():return list(map(int,input().split()))
t=int(input())
for _ in range(t):
n=int(input())
a=inp()
ind=[0]*(n+1);cnt=[0]*(n+1)
for i,x in enumerate(a):
ind[x]=i;cnt[x]=n-i-1
m=int(input())
for i in range(m):
a,b=inp()
if ind[b]<ind[a]:
a,b=b,a
cnt[b]+=1;cnt[a]-=1
if any([i not in cnt for i in range(n)]):
print("IMPOSSIBLE")
continue;
s=[0]*n
for i,x in enumerate(cnt[1:]):
s[x]=i+1
print(' '.join(map(str,reversed(s))))
728x90
'백준브실골 > Graph' 카테고리의 다른 글
백준 11112, Eight puzzle (2) | 2023.05.12 |
---|---|
백준 21940, 가운데에서 만나기 (0) | 2023.05.12 |
백준 18224, 미로에 갇힌 건우 (0) | 2023.02.23 |
백준 13459, 구슬 탈출 (0) | 2023.02.23 |
백준 17089, 세 친구 (0) | 2023.02.23 |
백준 1525, 퍼즐 (0) | 2023.02.22 |
백준 25515, 트리 노드 합의 최댓값 (0) | 2023.02.22 |
백준 18500, 미네랄 2 (0) | 2023.02.21 |
댓글