아이디어

  • 0-1 BFS 사용해서 동생위치 찾음
    • 처음 좌표 넣을떄 2의배수 모두 추가
    • 중간에 x2배(시간이 0) 다른것보다 먼저 수행해줘야함
    • priority_queue 사용해서 수행

 

시간복잡도 계산

  • 우선순위 큐 사용 : O(NlgN) = 1e5 * 20
  • BFS : O(V+E)
    • 노드 개수 : N
    • 간선 개수 : 최대 N
    • O(N)
  • 총합 : O(NlgN + N) : O(NlgN) > 가능

인트 계산

  • 가장 빠른시간 최대 1e5 > INT 가능

 

코드

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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <iostream>
#include <queue>
 
using namespace std;
typedef pair<intint> pi2;
 
bool chk[100010];
int main() {
    int N,K; cin >> N >> K;
    
    priority_queue<pi2, vector<pi2>, greater<pi2>> pq;
    // 시작값 큐에 넣어줌, 앞에는 시간, 뒤에는 노드
    pq.push(make_pair(0,N));
    fill(chk, chk+1000100);
    chk[N] = 1;
    if(N==K) {
        cout << 0 << '\n';
        return 0;
    }
    
    while(!pq.empty()) {
        int et = pq.top().first;
        int en = pq.top().second;
        pq.pop();
        
        if(en == K) {
            cout << et << '\n';
            return 0;
        }
        
        // 2배 먼저 해주기
        int en2 = en * 2;
        while(en2 <= 100000) {
            if(chk[en2]) break;
            
            chk[en2] = 1;
            pq.push(make_pair(et, en2));
            en2 = en2 * 2;
        }
        
        // 1더한것
        if(en+1 <= 100000) {
            if(chk[en+1== false) {
                chk[en+1= 1;
                pq.push(make_pair(et+1, en+1));
            }
            
        }
        
        
        // 1뺀것
        if(en-1 >= 0) {
            if(chk[en-1== false) {
                chk[en-1= 1;
                pq.push(make_pair(et+1, en-1));
            }
            
        }
    }
    return 0;
}
 
cs

 

문제유형

  • BFS - 0/1 : 다른 노드보다 우선 수행해줘야하는 조건이 있을때 사용

문제링크 : https://www.acmicpc.net/problem/9205

문제 추상화

  • 출발점에서 종료점까지 가는데
  • 최대 1000의 거리까지 갈 수 있음
  • 어느 지점 들려서 가면 갈수 있는지 확인

아이디어

  • bfs로 도착지 갈수 있는지확인
    • 그럼 각 점에서 다음 점으로 갈수 있는지는 어떻게 확인?
      • 반경 1000미터를 돌면서 확인하면 되지 않을까?
        • 그러면 정점이 너무 많아짐
        • BFS : O(V+E)
          • V : 모든 정점 : 9e8 > 시간초과
      • 편의점과 펜타포트를 기록해뒀다가 계속 탐색해보자
    • 그래서 펜타포트와 값이 같아지면 종료

시간복잡도 계산

  • 테스트 케이스 O(T)
  • 간선의 개수 : O(N^2)
  • BFS : O(V+E) = O(N^2)
  • 합 : O(T * N^2) > 가능

인트 계산

  • 거리가 될수 있는 최대값 = 32767 * 2 > 인트 가능

코드

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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#include <iostream>
#include <vector>
#include <cmath>
#include <queue>
 
using namespace std;
typedef pair<intint> pi2;
 
vector<pi2> v;
bool chk[110];
vector<int> adj[110];
 
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    
    int t; cin >> t;
    while(t--) {
        int N; cin >> N;
        
        v.clear();
        // 출발값
        int sty,stx;
        cin >> sty >> stx;
        v.push_back(make_pair(sty, stx));
        
        // 편의점 위치 배열
        
        for(int i=0; i<N; i++) {
            int ey, ex;
            cin >> ey >> ex;
            v.push_back(make_pair(ey, ex));
        }
        int eny, enx;
        cin >> eny >> enx;
        v.push_back(make_pair(eny, enx));
 
        
        // 인접 리스트 초기화
        for(int i=0; i<110; i++) adj[i].clear();
 
        for(int i=0; i<=N+1; i++) {
            int ey = v[i].first;
            int ex = v[i].second;
            
            for(int j=0; j<=N+1; j++) {
                if(i==j) continue;
                int ny = v[j].first;
                int nx = v[j].second;
                if(abs(ey - ny) + abs(ex - nx) <= 1000) {
                    adj[i].push_back(j);
                }
                
                
            }
 
        }
        
        // st에서부터 bfs 시작해 en도착하면 종료
        fill(chk, chk+1100);
        
        queue<int> q;
        q.push(0);
        chk[0= 1;
        
        bool sw = false;
        
        while(!q.empty()) {
            int eq = q.front(); q.pop();
            if(eq == N+1) {
                cout << "happy\n";
                sw = 1;
                break;
            }
            
            for(auto x : adj[eq]) {
                if(chk[x] == 1continue;
                q.push(x);
                chk[x] = 1;
            }
        }
        
        if(sw == falsecout << "sad\n";
        
        
        
    }
    return 0;
}
 
cs

문제유형

  • BFS - 조건
    • 특정 거리 이하의 경우에만 이동할 수 있는 경우
    • 해당 조건에 만족하는 경우만 간선에 추가한 뒤 BFS 수행

문제링크 : https://www.acmicpc.net/problem/2887


아이디어

  • 모든 행성을 터널로 연결 >> MST
    • Kruscal 사용해서 MST 구하자
  • 간선의 개수 : E = N(N+1)/2 = 1e10/2 = 5e9
    • MST 시간복잡도 : O(ElgE) > 시간초과
    • 간선을 모두 넣는 경우에는 시간초과가 발생
  • 문제 중 비용 = min(x, y, z)을 이용
    • x,y,z 좌표의 차이를 각각 넣고, 이중 최소값만 사용하면됨
      • 크루스칼에서 자연스럽게 최소의 간선만 적용될 것임
    • 모든 노드의 간선을 넣지말고. 정렬한뒤 근접한 것만 적용
      • 어짜피 최소값만 MST에서 살아남게됨
      • 그러므로 정렬 시킨다음에 인접한 것이 가장 작은 값

시간복잡도 계산

  • x,y,z 좌표에 대해서 각각 정렬 : O(3 * NlgN)
    • 인접한 노드에 대해서 간선 추가 : O(3 * N)
    • MST 시간복잡도 : ElgE
      • 간선의 개수(E): 3N
      • 3Nlg3N
    • 총합 : O(3NlgN + 3N + 3Nlg3N) = O(NlgN)

인트 계산

  • 간선 의 길이 최대값 : 2e9 > INT 가능
  • 최소비용 : 2e9 *N-1 >> long long 사용

코드

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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include <iostream>
#include <tuple>
#include <algorithm>
#include <vector>
#include <cmath>
 
using namespace std;
typedef tuple<intintint> ti3;
typedef pair<intint> pi2;
typedef long long ll;
 
vector<ti3> edge;
int p[100010];
vector<pi2> xnode;
vector<pi2> ynode;
vector<pi2> znode;
 
int N;
 
int find(int v) {
    if(p[v] < 0return v;
    return p[v] = find(p[v]);
}
 
bool is_diff_group(int v1, int v2) {
    v1 = find(v1); v2 = find(v2);
    if(v1 == v2) return 0;
    
    if(p[v1] == p[v2]) p[v1]--;
    
    if(p[v1] < 0) p[v2] = v1;
    else p[v1] = v2;
    return 1;
    
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    
    fill(p, p+100010-1);
    cin >> N;
    
    // 각 좌표 넣기
    // 이때 노드 인덱스랑 같이 넣어줌 정렬후 확인하기 위해
    for(int i=0; i<N; i++) {
        int ex, ey, ez;
        cin >> ex >> ey >> ez;
        xnode.push_back(make_pair(ex, i));
        ynode.push_back(make_pair(ey, i));
        znode.push_back(make_pair(ez, i));
    }
    
    // 간선수 줄이기위해 정렬
    sort(xnode.begin(), xnode.end());
    sort(ynode.begin(), ynode.end());
    sort(znode.begin(), znode.end());
    
    // 인접한 노드를 엣지에 추가
    for(int i=0; i<N-1; i++) {
        edge.push_back({abs(xnode[i].first - xnode[i+1].first),xnode[i].second,xnode[i+1].second});
        edge.push_back({abs(ynode[i].first - ynode[i+1].first),ynode[i].second,ynode[i+1].second});
        edge.push_back({abs(znode[i].first - znode[i+1].first),znode[i].second,znode[i+1].second});
    }
    
    // 간선들 정렬
    sort(edge.begin(), edge.end());
    
    int cnt=0;
    ll ans=0;
    // Kruscal 수행
    for(int i=0; i<edge.size(); i++) {
        int cost, a,b; tie(cost,a,b) = edge[i];
        if(!is_diff_group(a,b)) continue;
        
        cnt++;
        ans += cost;
        if(cnt==N-1break;
    }
    
    cout << ans << '\n';
    
    
    return 0;
}
 
cs

문제유형

  • MST - 간선의 특수 조건
    • 간선의 비용이 특수한 경우
    • 일반적으로 하면 간선의 개수가 많아서 시간초과 발생
    • 간선의 조건 활용해 그리디하게 사용 가능

+ Recent posts