문제 링크

풀이

eraseBlock();
rootedClusterCheck();
flyClusterDown();

eraseBlock();

왼쪽, 오른쪽에서 막대기를 던질 때 해당하는 block을 제거하는 로직.

 

rootedClusterCheck();

rooted → 땅에 박혀있는 이라는 의미로 변수명 지었다. 땅(row == 0) 까지 연결되어 있는 클러스터는 땅으로 떨어지지 않기 때문에 먼저 땅과 연결되어 있는 클러스터들을 체크해줬다.

체크한 방법은 row == 0에 있는 것 중에서 x가 있으면 그걸 시작점으로 dfs를 돌면서 연결되어 있는 것들을 체크했다.

 

flyClusterDown();

앞에서 땅과 연결되어 있는 클러스터들은 체크가 됐다. 그렇다면 입력 테이블에서 'x'이면서 땅과 연결된 클러스터로 체크되지 않은 것은 모두 공중에 있는 클러스터일 것이다. 문제조건에 두 개 이상의 클러스터는 공중에 있지 않다고 했으므로 해당하는 x를 만나면 거기서 dfs를 통해 공중에 있는 클러스터들을 체크해줬다.

그리고 이 클러스터를 땅이나 만나는 미네랄에 연결시켜줘야 한다. 이 클러스터는 전체적으로 똑같은 col만큼 아래로 하강하는데 이 값을 효율적으로 구하기 위해 dfs돌면서 각 column의 가장 작은 row값을 따로 저장해 뒀다.

int findDownLength() {
  int minLength = 9999999;
  for(int j=0;j<c;++j) {
    if(columnList[j] == 999999) continue;
    for(int i=0;i<r;++i) {
      if(table[i][j] == 'x') {
        if(i == columnList[j]) {
          minLength = min(minLength, i);
          break;
        } else {
          minLength = min(columnList[j] - i - 1, minLength);
        }
      }
    }
  }
  return minLength;
}

이 값들은 위와 같은 코드에 사용되는데 땅부터 row를 증가시키면서 찾다가 테이블에 'x'를 만났다면 두 가지 경우중 하나이다.

첫 번째는 공중에 떠있는 자기자신을 만났을 때,

두 번째는 다른 땅과 연결된 클러스터를 만났을 때이다.

전자는 자기를 만났기 때문에 자기 위쪽은 탐색할 필요 없다. 그래서 클러스터를 몇칸 땅으로 이동시킬지에 대한 변수인 minLength를 자기 row값으로 min(minLength, i)로 최신화 시켜주었다.

후자는 지금 만난 x보다 더 위에도 x가 존재할 수 있고, 그 때에는 minLength가 더 작아지기 때문에 추가적인 탐색이 필요해 break를 걸지 않았다.

이렇게 몇칸 아래로 내릴지 구한다음 공중에 떠있는 클러스터들은 모두 체크가 되어 있기 때문에 그 칸만큼 내려준다.

이 3가지 과정을 N번 진행하면 문제가 풀린다.

코드

#include <iostream>
#include <vector>

using namespace std;

char table[101][101];

int r, c;
bool isrootedCluster[101][101];
void rootedClusterClear() {
  for(int i=0;i<r;++i) {
    for(int j=0;j<c;++j) {
      isrootedCluster[i][j] = false;
    }
  }
}

vector<int> stickThrowRow;

void input() {
  cin >> r >> c;
  for(int i=0;i<r;++i) {
    for(int j=0;j<c;++j) {
      cin >> table[r-i-1][j];
    }
  }
  int n;
  cin >> n;
  int temp;
  for(int i=0;i<n;++i) {
    cin >> temp;
    stickThrowRow.push_back(temp); 
  }
}

bool blockErase(int row, int col) {
  if(table[row][col] == 'x') {
    table[row][col] = '.';
    return true;
  }
  return false;
}

void eraseBlock(int throwIdx, bool isRightToLeft) {
  if(isRightToLeft) {
    for(int i=0;i<c;++i) {
      if(blockErase(throwIdx, i)) return;
    }
  } else {
    for(int i=c-1;i>=0;--i) {
      if(blockErase(throwIdx, i)) return;
    }
  }
}

int dx[] = {0,0,1,-1};
int dy[] = {1,-1,0,0};
bool dfsRangeChk(int nx, int ny) {
  return (0 <= nx && nx < c && 0 <= ny && ny < r);
}

bool dfsVisited[101][101];
void dfsVisitedClear() {
  for(int i=0;i<r;++i) {
    for(int j=0;j<c;++j) {
      dfsVisited[i][j] = false;
    }
  }
}

bool columnCheckNeeded = false;
int columnList[101];
void clearColumnList() {
  for(int i=0;i<101;++i) {
    columnList[i] = 999999;
  }
}

void dfs(int row, int col) {
  for(int i=0;i<4;++i) {
    int nx = col + dx[i];
    int ny = row + dy[i];
    if(dfsVisited[ny][nx] == false && dfsRangeChk(nx, ny)) {
      if(table[ny][nx] == 'x'){
        if(columnCheckNeeded) {
          columnList[nx] = min(columnList[nx], ny);
        }
        dfsVisited[ny][nx] = true;
        dfs(ny, nx);
      }
    }
  }
}

void pasteRootedResult() {
  for(int i=0;i<r;++i) {
    for(int j=0;j<c;++j) {
      if(dfsVisited[i][j] == true) {
        isrootedCluster[i][j] = true;
      }
    }
  }
}

void rootedClusterCheck() {
  for(int i=0;i<c;++i) {
    if(isrootedCluster[0][i] == false && table[0][i] == 'x') {
      dfsVisitedClear();
      isrootedCluster[0][i] = true;
      dfs(0, i);
      pasteRootedResult();
    } 
  }
}

void findflyCluster(int i, int j) {
  dfsVisitedClear();
  dfsVisited[i][j] = true;
  columnList[j] = i;
  dfs(i, j);
}

int findDownLength() {
  int minLength = 9999999;
  for(int j=0;j<c;++j) {
    if(columnList[j] == 999999) continue;
    for(int i=0;i<r;++i) {
      if(table[i][j] == 'x') {
        if(i == columnList[j]) {
          minLength = min(minLength, i);
          break;
        } else {
          minLength = min(columnList[j] - i - 1, minLength);
        }
      }
    }
  }
  return minLength;
}

void downCluster() {
  int downLength = findDownLength();
  for (int j = 0; j < c; ++j) {
    for (int i = 0; i < r; ++i) {
      if(dfsVisited[i][j] == true) {
        table[i][j] = '.';
        table[i-downLength][j] = 'x';
      }
    }
  }
}

void flyClusterDown() {
  for(int i=0;i<r;++i) {
    for(int j=0;j<c;++j){
      if(isrootedCluster[i][j] == false && table[i][j] == 'x') {
        clearColumnList();
        columnCheckNeeded = true;
        findflyCluster(i, j);
        columnCheckNeeded = false;
        downCluster();
        return;
      }
    }
  }
}

void processing() {
  for(int i=0;i<stickThrowRow.size(); ++i) {
    eraseBlock(stickThrowRow[i]-1, i%2==0);
    rootedClusterCheck();
    flyClusterDown();
    rootedClusterClear();
  }
}

void printAnswer() {
  for(int i=0;i<r;++i) {
    for(int j=0;j<c;++j) {
      cout << table[r-i-1][j];
    }
    cout << '\n';
  }
}

int main(void) {
  // freopen("b2933.txt", "r", stdin);
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  input();
  processing();
  printAnswer();
}

'알고리즘' 카테고리의 다른 글

백준 2916 자와 각도기 c++  (0) 2020.09.15
백준 2210 숫자판 점프 c++  (0) 2020.09.15
백준 2776 CPP, js  (0) 2020.09.04
[javascript] b1072.js  (0) 2020.09.03
[프로그래머스] 정수삼각형 c++ 재귀로 풀기  (0) 2020.07.04

재귀 부분에서 dfs(nx,ny,cnt+1)을 

++cnt로 했는데 틀렸습니다 가 나왔다. 차이는 나중에 생각해 봐야겠다. 

새로 배운 것

1. 플러드 필에서 이동할 때 썼던 int dx,dy 배열을 한번에 2차원 배열로 사용하는 방법

2. 앞에것 을 방문했는지를 확인하는 데에 원래 배열을 만들어서 이전에 방문했던 지점을 

저장하고, for문을 이용해서 그 것을 매번 다음 nx,ny를 방문할 때마다 반복해야 했다. 

하지만 이 코드로 bool ch에 배열 number로 저장해서 한번에 찾을 수 있다는 걸 알았다. 

3. 백트래킹에 대해 아주 많이 생각해 보게 되었다. 



#include <iostream>
using namespace std;
int r, c;
char a[22][22];
bool ch[26];
int dd[][2] = { { 1,0 },{ -1,0 },{ 0,1 },{ 0,-1 } };
int ans = 0;
void dfs(int x, int y, int cnt) {
       if (cnt > ans) ans = cnt;
       for (int k = 0; k < 4; ++k) {
               int nx = x + dd[k][0];
               int ny = y + dd[k][1];
               if (0 <= nx&&nx < r && 0 <= ny&&ny < c) {
                      if (ch[a[nx][ny] - 'A'] == false) {
                              ch[a[nx][ny] - 'A'] = true;
                              dfs(nx, ny, cnt+1);
                              ch[a[nx][ny] - 'A'] = false;
                      }
               }
       }
}
int main() {
       cin >> r >> c;
       for (int i = 0; i < r; ++i) {
               cin >> a[i];
       }
       ch[a[0][0] - 'A'] = true;
       dfs(0, 0, 1);
       cout << ans;
       return 0;
       
}

'알고리즘' 카테고리의 다른 글

[DP] 백준 동전 2 2294  (0) 2018.04.02
[DP] 백준 2011 암호코드  (0) 2018.01.02
[그래프] 백준 5567 결혼식  (0) 2017.12.13
[EAZY] 백준 1065번 한수  (0) 2017.08.17
[EAZY] 백준 4673 셀프넘버  (0) 2017.08.15
트리

사이클이 없는 그래프

정점의 개수 V

간선의 개수 V-1



루트 있는 트리


부모(Parent)


그래프가 있으면 루트에 가까운 것이 부모

루트는 부모가 없다. 


자식(Children)


​부모 아래에 달려있는 노드

가장 아래층에 있는 노드 => 단말 정점 (Terminal Node) (Leaf Node)


형제(Sibiling)

​같은 부모를 가지면 형제


깊이(Depth)


​루트에서 부터의 거리 (루트의 깊이를 0으로 하나 1로 하나의 차이가 있다)



높이(Height)

깊이 중에서 가장 큰 값

조상, 자손(Ancestor, Descendent)

p->q로 갈 수 있을 때(형제 위치로는 갈 수 없음)
p가 q보다 루트에 가까우면
p는 q의 조상
q는 p의 자손


이진 트리(Binary Tree)

자식을 최대 2개만 가지고 있는 트리




트리의 표현

1. 그래프와 같은 방식으로 저장할 수 있다.

2. 트리의 모든 노드는 루트를 제외하고 모두 부모를 가지므로 부모만 저장하는 방식

2.의 장점 => 부모를 찾는데 O(1)만큼 걸린다. 

2의 단점 => 자식을 찾는데 O(V)만큼 걸린다. 

3. 이진트리의 경우 배열로 표현할 수 있다. 

부모를 x로 자식을 2x, 2x+1로 설정해서 배열로 저장

3의 단점 => 한쪽으로만 연결된 트리를 예로 들 경우 8개를 저장하기 위해 256개의 저장공간이 필요함

이진 트리가 꽉 차는 방식으로 차도록 해결할 수 있는 문제는 이런 방식으로 사용하면 아주 좋음 



boj.kr/5567

문제

상근이는 자신의 결혼식에 학교 동기 중 자신의 친구와 친구의 친구를 초대하기로 했다. 상근이의 동기는 모두 N명이고, 이 학생들의 학번은 모두 1부터 N까지이다. 상근이의 학번은 1이다.

상근이는 동기들의 친구 관계를 모두 조사한 리스트를 가지고 있다. 이 리스트를 바탕으로 결혼식에 초대할 사람의 수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 상근이의 동기의 수 n (2 ≤ n ≤ 500)이 주어진다. 둘째 줄에는 리스트의 길이 m (1 ≤ m ≤ 10000)이 주어진다. 다음 줄부터 m개 줄에는 친구 관계 ai bi가 주어진다. (1 ≤ ai < bi ≤ n) ai와 bi가 친구라는 뜻이며, bi와 ai도 친구관계이다. 

출력

첫째 줄에 상근이의 결혼식에 초대하는 동기의 수를 출력한다.




풀이과정
첫번째 for : 양방향 그래프로 입력을 받는다. 
두번째 for : 1과 친구인 관계를 ch에 1로 저장하고 queue에 친구관계인 node를 push한다.
세번째 while : queue에 들어간 node를 하나씩 꺼내서 그 것과 연결된 노드 중 방문하지 않은 노드의 ch에 2를 저장한다.
마지막 for : ch가 1인 것과 2인 것의 개수를 센다.

#include <iostream>
#include <vector>
#include <queue>
using namespace std;
queue<int> s;
vector<int> a[10001];
int ch[10001] = {0, };
int ans = 0;
int n;
int main() {
       cin >> n;
       int t;
       cin >> t;
       for (int i = 0; i < t; ++i) {
               int temp1, temp2;
               cin >> temp1 >> temp2;
               a[temp1].push_back(temp2);
               a[temp2].push_back(temp1);
       }
       int temlen = a[1].size();
       for (int i = 0; i < temlen; ++i) {
               ch[a[1][i]] = 1;
               s.push(a[1][i]);
       }
       while (!s.empty()) {
               int temp = s.front();
               s.pop();
               int len = a[temp].size();
               for (int j = 0; j<len; ++j)
                      if (ch[a[temp][j]] == 0) {
                              ch[a[temp][j]] = 2;
                      }
       }
       for (int i = 2; i <= n; ++i) {
               if (ch[i] == 2 || ch[i] == 1) {
                      ans++;
               }
       }
       cout << ans;
       return 0;
}


'알고리즘' 카테고리의 다른 글

[DP] 백준 2011 암호코드  (0) 2018.01.02
[그래프] 백준 1987 알파벳  (0) 2017.12.14
[EAZY] 백준 1065번 한수  (0) 2017.08.17
[EAZY] 백준 4673 셀프넘버  (0) 2017.08.15
백준 C++ 11721번  (0) 2017.08.15

+ Recent posts