백준: Class 5 - 12100, 16724

3 분 소요


</br> 클래스 5 계속
</br>

12100: 2048 (Easy)

https://www.acmicpc.net/problem/12100

void up(){
    stack<int> st;
    for(int j = 0; j < n; j++){
        for(int i = n-1; i >= 0; i--){
            if( mmap[i][j] ) st.push(mmap[i][j]);
            mmap[i][j] = 0;
        }
        if( st.empty() ) continue;
        queue<int> q;
        int a = st.top();
        st.pop();
        while( st.size() ){
            int b = st.top();
            st.pop();
            if( a == b ){
                q.push(a*2);
                a = 0;
            }
            else{
                if( a ) q.push(a);
                a = b;
            }
        }
        if( a ) q.push(a);
        int i = 0;
        while( q.size() ){
            mmap[i++][j] = q.front();
            q.pop();
        }

    }
}

void down();
void lef()
void righ();

void func(int d){
    if( d == 5 ){
        for(int i = 0; i < n; i++){
            for(int j = 0; j < n; j++){
                ans = max(ans, mmap[i][j]);
            }
        }
        return;
    }

    vector< vector<int> > t = mmap;
    up();
    func(d+1);
    mmap = t;

    down();
    func(d+1);
    mmap = t;

    righ();
    func(d+1);
    mmap = t;

    lef();
    func(d+1);
    mmap = t;
}

12
문제에 게임 링크를 보자마자 홀린 듯이 했다 추억의 게임… 아직 실력은 죽지 않았다
아무튼, 구현 문제였다
각 방향으로 움직일 때, 그걸 스택에 쌓아 둔다.
그리고 꺼내면서, 결과를 큐에 넣는다.
그리고 큐를 팝하며 결과를 배열에 저장한다.

ex)
4
4 2 2 0
2 2 4 0
2 4 4 0
2 4 0 0

up()을 하면
j == 1
stack: 4 2 2 2
queue: 4 4 2

j == 2
stack: 2 2 4 4
queue: 4 4 4

j == 3
stack: 2 4 4
queue: 2 8

j == 4
stack:
queue:

따라서
4 4 2 0
4 8 8 0
2 0 0 0
0 0 0 0

down lef righ 함수는 up의 포문에서 i랑 j 증감이나 위치만 반대로 해 주면 되므로 생략한다
</br>

16724: 피리 부는 사나이

https://www.acmicpc.net/problem/16724

int mmap[1001][1001];
int dx[4] = {-1, 1, 0, 0};
int dy[4] = {0, 0, -1, 1};
int ind[1000001];

struct UnionFind{
    vector<int> parent;
    UnionFind(int n) : parent(n){
        for(int i = 0; i < n; i++){
            parent[i] = i;
        }
    }
    int f(int u){
        if( u == parent[u] ) return u;
        return parent[u] = f(parent[u]);
    }
    void merg(int u, int v){
        u = f(u), v = f(v);
        if( u == v ) return;
        if( u < v ) swap(u, v);
        parent[u] = v;
    }
};

// in main()
    for(int i = 0; i < n; i++){
        for(int j = 0; j < m; j++){
            char c;
            cin >> c;
            if( c == 'U' ) mmap[i][j] = 0;
            else if( c == 'D' ) mmap[i][j] = 1;
            else if( c == 'L' ) mmap[i][j] = 2;
            else if( c == 'R' ) mmap[i][j] = 3;
        }
    }

    UnionFind uf = UnionFind(n*m);

    for(int i = 0; i < n; i++){
        for(int j = 0; j < m; j++){
            int nx = i + dx[mmap[i][j]];
            int ny = j + dy[mmap[i][j]];
            if( nx < 0 || n <= nx || ny < 0 || m <= ny ) continue;
            uf.merg(i*m+j, nx*m+ny);
        }
    }
    for(int i = 0; i < n*m; i++){
        uf.f(i);
    }

    int cnt = 0;
    for(int i = 0; i < n*m; i++){
        if( ind[uf.parent[i]] ) continue;
        ind[uf.parent[i]] = 1;
        cnt++;
    }
    cout << cnt << endl;

다행스럽게도 얘는 보자마자 union find라고 알겠더라
(i,j)에서 (nx,ny)로 이동한다면, (i,j)와 (nx,ny)를 병합하고 그 기준은 작은 번호를 부모로 했다(따라서 랭크가 필요 없음).
마지막에 업데이트 된 parent 배열에서, 다른 부모들의 수를 세 주면 된다.

ex) 백준 예제
3 4
DLLL
DRLU
RRRU

초기 parent는 자기 자신
 0  1  2  3
 4  5  6  7
 8  9 10 11

(0,0)은 D므로 낮은 번호 기준으로 합침
 [0]  1  2  3
 [0]  5  6  7
  8   9 10 11

(0,1)은 L이므로 낮은 번호 기준으로 합침
 [0]  [0]  2  3
  0    5   6  7
  8    9  10 11

...

 0  0  0  0
 0  5  5  0
 0  0  0  0
ans = 2

참고로, 마지막에 parent 배열이 업데이트가 안 되었을 수도 있어서

    for(int i = 0; i < n*m; i++){
        uf.f(i);
    }

이거 한 번 넣어서 다 업데이트해 주고 답을 세면 된다.
</br>


오늘은 8월 22일
월요일인 내일부터 Swift로 ios 개발 수업을 듣기로 했다 그래서 문제 풀이는 많이는 못하겠네
그래도 어차피 포스트는 밀려 있긴 하다 이 포스트는 9월 넘어서 올라갈 것 같다
</br>

댓글남기기