짬뽕얼큰하게의 맨땅에 헤딩 :: '알고리즘' 카테고리의 글 목록 (29 Page)

summary

  • Find the edge that can be removed from a connected graph with n nodes and m edges to make it a tree.

approach

  • Use a union-find data structure to keep track of connected components in the graph
  • Iterate through the edges, and for each edge, check if the two nodes are in the same component
  • If they are, then the edge is the redundant one
  • Otherwise, union the two components.

complexity

  • O(n + m log n) due to the union-find operations, where n is the number of nodes and m is the number of edges.

explain

  • The solution uses a union-find data structure to keep track of connected components in the graph
  • The union-find data structure is initialized with each node as its own component
  • Then, for each edge, the solution checks if the two nodes are in the same component by calling the `disjoint` function
  • If they are, then the edge is the redundant one, and the solution returns it
  • Otherwise, the solution unions the two components by calling the `uf` function
  • The `disjoint` function is used to find the root of a node, and the `uf` function is used to union two components.

Solution Code:


class Solution {
public:
    int uf[1001];
    int disjoint(int x){
        if(x == uf[x]) return x;
        return uf[x] = disjoint(uf[x]);
    }
    vector findRedundantConnection(vector>& edges) {
        for(int i = 0 ; i <= 1000; i++){
            uf[i] = i;
        }
        vector ans;
        for(int i = 0 ; i < edges.size(); i++){
            int a = edges[i][0];
            int b = edges[i][1];
            if(disjoint(a) != disjoint(b)){
                uf[disjoint(a)] = disjoint(b);
            } else{
                ans.push_back(a);
                ans.push_back(b);
            }
        }
        return ans;
    }
};
블로그 이미지

짬뽕얼큰하게

,

실수: 문자열의 길이가 1일경우를 생각하지 못해서 시간을 낭비.

시간 복잡도: O(N^2 +알파..?)


시간복잡도 계산이 잘 안된다. 

12번 라인과 17번 라인이 서로 의존적이다. 

n이1인경우 strncmp는 거의 연산비용이 들지 않게되고...

그렇다고 n을 N으로 키우면... 중간의 while(right < N) 반복문 접근수가 줄어든다.

잘 모르겠다.


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
#include <string>
#include <vector>
#include <iostream>
#include <string.h>
 
using namespace std;
 
int solution(string s) {
    int answer = 1001;
    int N = s.length();
    if (N == 1return 1;
    for (int n = 1; n < N; n++) {
        string str = "";
        int left = 0, right = n;
        int equalCnt = 1;
        while(right < N){
            if (strncmp(&s[left], &s[right], n) == 0) {
                equalCnt++;
            }
            else {
                if (equalCnt == 1) {
                    str = str + s.substr(left, n);
                }
                else {
                    str = str + to_string(equalCnt) + s.substr(left, n);
                }
                left = right;
                equalCnt = 1;
            }
            right += n;
        }
        if (equalCnt == 1) {
            str = str + s.substr(left, n);
        }
        else {
            str = str + to_string(equalCnt) + s.substr(left, n);
        }
 
        if (answer > str.length()) {
            answer = str.length();
        }
        //std::cout << str << endl;
    }
    return answer;
}
 
cs


블로그 이미지

짬뽕얼큰하게

,

입국심사.

처음엔 당황했지만.. 생각해보니 풀 수 있었다.

이분탐색 문제라는걸 몰랐으면 더 힘들었을 것 같다.



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
#include <string>
#include <vector>
 
using namespace std;
 
long long solution(int n, vector<int> times) {
    long long answer = 1000000000000000000;
    long long l = 1;
    long long r = answer;
 
    while (l <= r) {
        long long mid = (l + r) / 2;
        int simsa = times.size();
        long long person = 0;
        for (int i = 0; i < simsa; i++) {
            person += mid / times[i];
        }
        if (person >= n) {
            answer = mid;
            r = mid - 1;
        }
        else {
            l = mid + 1;
        }
    }
 
    return answer;
}
cs
블로그 이미지

짬뽕얼큰하게

,

BFS 이용해서 풀었다.



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
#include <string>
#include <vector>
#include <queue>
 
using namespace std;
bool visited[20001];
vector<int> link[20001];
struct _pair {
    int num;
    int cnt;
};
queue<_pair> que;
int maxCnt = 0;
int solution(int n, vector<vector<int>> edge) {
    int answer = -1;
    int edgeN = edge.size();
    for (int i = 0; i < edgeN; i++) {
        int a = edge[i][0];
        int b = edge[i][1];
        link[a].push_back(b);
        link[b].push_back(a);
    }
    visited[1= true;
    que.push({ 10 });
    while (!que.empty()) {
        _pair pair = que.front();
        que.pop();
        if (pair.cnt > maxCnt) {
            maxCnt = pair.cnt;
            answer = 1;
        }
        else if (pair.cnt == maxCnt) {
            answer++;
        }
        for (int i = 0; i < link[pair.num].size(); i++) {
            int a = pair.num;
            int b = link[a][i];
            if (visited[b]) continue;
            visited[b] = true;
            que.push({ b,pair.cnt + 1 });
        }
    }
 
    return answer;
}
cs
블로그 이미지

짬뽕얼큰하게

,

크루스칼로 풀었다.

/**

실수:

disjoint함수의 두 a,b값이 다른 경우 uf[disjoint(a)] = disjoint(b); 최상위 번호를 찾아 넣어줘야하는데...

uf[a] = disjoint(b) 로 넣어주었다.. ㅠㅠ

이렇게 되면 두집합이 합쳐질때 최상위번호가 바뀌는게 아니라.. 중간쯔음에서 바뀌기 때문에... 집합 전체가 합쳐지지 않는다.

오히려 이건 가능하다.

uf[disjoint(a)] = b

b는 최상위가 아니여도... a의 최상위를 b로 바꿔주었기때문에.. disjoint 함수를 부르게되면 최상위 번호로 갱신된다.


**/



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
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
bool cmp(const vector<int>& a, const vector<int>& b) {
    return a[2< b[2];
}
int uf[100];
int disjoint(int x) {
    if (uf[x] == x) return x;
    return uf[x] = disjoint(uf[x]);
}
int solution(int n, vector<vector<int>> costs) {
    int answer = 0;
    for (int i = 0; i < n; i++) {
        uf[i] = i;
    }
 
    int row = costs.size();
 
    sort(costs.begin(), costs.end(), &cmp);
 
    for (int i = 0; i < row; i++) {
        int a = costs[i][0];
        int b = costs[i][1];
        int cost = costs[i][2];
        if (disjoint(a) != disjoint(b)) {
            uf[disjoint(a)] = disjoint(b);
            answer += cost;
        }
        else {
            continue;
        }
    }
 
    return answer;
}
 
cs


블로그 이미지

짬뽕얼큰하게

,

프로그래머스(programmers) N으로 표현

/**
1. 빼기와 나누기의 경우 순서가 바뀌는경우 결과값이 달라진다.
처음에 최적화를 한답시고, i/2+1 까지만 돌렸다가, WA를 받았다. 
이 점을 확인 한 후 i-1까지 돌렸다.

2. newN(222,333,44444) 의 숫자를 만들고.... 만들어야 하는 최종 숫자와 비교를 하지 않았다.
단순한 실수인데... 반례를 찾느라 한시간이 걸렸다. ㅜㅜ
구현 도중에도 검사해야겠다는 생각을 하지 않았다.;;;;;;;;;;;;
**/

 

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
#include <string>
#include <vector>
using namespace std;
 
vector<int> v[9];
int solution(int N, int number) {
    if (N == number) return 1;
    for (int i = 0; i < 9; i++) {
        v[i].clear();
    }
    int newN = N;
    v[1].push_back(N);
    for (int i = 2; i < 9; i++) {
        newN = 10 * newN + N;
        v[i].push_back(newN);
        if (newN == number) return i;
 
        for (int j = 1; j < i; j++) {
            for (int a = 0; a < v[i - j].size(); a++) {
                for (int b = 0; b < v[j].size(); b++) {
                    if (v[i - j][a] == 0 || v[j][b] == 0continue;
                    int res = v[i - j][a] + v[j][b];
                    v[i].push_back(res);
                    if (res == number) return i;
 
                    res = v[i - j][a] - v[j][b];
                    v[i].push_back(res);
                    if (res == number) return i;
 
                    res = v[i - j][a] * v[j][b];
                    v[i].push_back(res);
                    if (res == number) return i;
 
                    if (v[j][b] == 0continue;
                    res = v[i - j][a] / v[j][b];
                    v[i].push_back(res);
                    if (res == number) return i;
                }
            }
        }
    }
    return -1;
}
cs
블로그 이미지

짬뽕얼큰하게

,

1. 자료구조:


1
2
3
4
5
6
7
8
9
10
11
struct student{
 
char name[2];
 
unsigned long nameKey;
 
};
 
 
 
student gAllStudent[100];
cs

 


2. hash 함수: unsigned long getNameKey(char* name);



위와 같은 상황에서 이름의 hash값을 이용하여 gAllStudent에 있는 여러명의 학생 이름을 빠르게 찾을 때 한 실수다.


name1, name2 를 찾는다 했을때, getNameKey로 얻은 hash값을 nameKey1, nameKey2라고 하면


1
2
3
4
5
6
7
8
9
 
 for(int i = 0 ; i < 100; i++) {
  if (gAllStudent[i].nameKey == nameKey1) {
    if(strcmp(gAllStudent[i].name, name1) == 0) { ~~~~}
  }
  else if(gAllStudent[i].nameKey == nameKey2) {
    if(strcmp(gAllStudent[i].name, name2) == 0) { ~~~~}
  }
}

cs

 



위와 같이 작성했다..

그런데.. hash값이기 때문에, name1, name2이름은 다르고 nameKey1과 nameKey2 가 같은 경우가 존재한다.


이런 경우 name2도 첫번째 if문만 들어가기때문에... 문제가 발생한다. 따라서 else if문을 if문으로 변경하여 가볍게 해결할 수있다.


위 실수를하여.. 원인 분석에 꽤 많은 시간이 들어 정리해 놓는다.






블로그 이미지

짬뽕얼큰하게

,

VS Code Problem Solving용 환경설정


작업 당시 운영체제: Ubuntu 18.04 64bit


VS Code를 활용하여 백준, 알고스팟, 코드 포스 등 여러 문제를 풀기위한 간단한 환경설정들이 검색해도 나오지 않아, 여기에 정리한다.


내가 VS 코드를 처음 설치하고 부딪힌 문제는 총 두개이다.

1. 어떻게 실행하지? -> Code Runner 이용

2. 인풋을 어떻게 입력하지? -> 설정 변경


1. VS Code 설치 : 생략


2. extension의 C/C++ 설치

   나는 C/C++ 를 사용하므로 해당 extension을 설치하였다.


3. code runner 설치

   빌드 및 실행하기 위한 code runner 설치


4. File -> preference -> setting에 들어 간 후

extensions -> Run Code configuration -> Run In Terminal checking!!!


5. 마우스 오른쪽 클릭, Run Code를 통해 실행


6. 터미널창에 입력이 가능한지 확인



VS Code를 사용하기위한 5분 설정 팁이다. Code Runner만 설치하여 사용할 시 output에 실행 결과가 나타나게 되는데, 이 output창에는 입력을 넣을 수가 없다.


따라서 PS를 위한 입력을 주기위해서는 위와 같은 세팅을 통해, 터미널에서 실행하는 것으로 변경 해야한다.


나도 시행착오 끝에 알아낸 방법인데, 

더 좋은 방법이 있다면 댓글로 정보 공유 부탁드립니다.  :D



블로그 이미지

짬뽕얼큰하게

,

못풀었다.

종만북 코드를 이해하고 책을 보지않고 따라해보았다.


leaf에서 leaf까지의 최대값과 leaf에서 root까지의 최대값의 최대값이 정답이 되는것으로 나눈것을 생각하지 못했다. 더 깊이 생각하는 습관을 가져야겠다.


트리 탐색시 다음노드들의 리턴값을 벡터에 저장하여 높이를 뽑아내는 패턴도 기억 해야겠다는 생각을 했다.


트리 탐색 기본 구조도 익혔고, 트리 생성 기본 구조도 익힐 수 있었다.


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
91
92
93
94
95
96
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct Pair{
    int y;
    int x;
    int r;
};
struct TreeNode{
    vector<TreeNode*> children;
};
 
 
Pair wall[101];
int longest;
int N, T;
 
int sq(int x){
    return x * x;
}
bool enclose(int a, int b){
    if(wall[a].r <= wall[b].r) return false;
 
    int y1 = wall[a].y;
    int x1 = wall[a].x;
    int r1 = wall[a].r;
    int y2 = wall[b].y;
    int x2 = wall[b].x;
    int r2 = wall[b].r;
    if(sq(r1 - r2) <= sq(x1 - x2) + sq(y1 - y2)){
        return false;
    }
    return true;
}
 
bool isChild(int parent, int child){
    if(parent == child) return false;
    if(!enclose(parent, child)) return false;
    for(int i = 0 ; i < N; i++){
        if(i == parent || i == child) continue;
        if(enclose(parent, i) && enclose(i, child)) return false;
 
    }
    return true;
}
TreeNode* getTree(int root){
    TreeNode* node = new TreeNode();
    for(int i = 0 ; i < N; i++){
        if(isChild(root, i)){
            node->children.push_back(getTree(i));
        }
    }
 
    return node;
}
 
 
int height(TreeNode* root){
    int s = root->children.size();
    vector<int> heights;
    for(int i = 0 ; i < s; i++){
        heights.push_back(height(root->children[i]));
    }
    if(heights.empty()) return 0;
    int h_s = heights.size();
    if(h_s >= 2){
        sort(heights.begin(), heights.end());
        longest = max(longest, heights[h_s - 1+ heights[h_s - 2+ 2);
    }
    return heights.back() + 1;
}
bool cmp(Pair a, Pair b){
    if(a.r < b.r) return false;
 
    return true;
}
 
int main(void){
    scanf("%d"&T);
    while(T--){
        longest = 0;
        scanf("%d"&N);
        for(int i = 0 ; i < N; i++){
            int x, y, r;
            scanf("%d %d %d"&x, &y, &r);
            wall[i] = {y, x, r};
        }
 
        sort(wall, wall + N, cmp);
 
 
        TreeNode* root = getTree(0);
        printf("%d\n", max(longest, height(root)));
    }
}
cs


블로그 이미지

짬뽕얼큰하게

,

영역 구하기 응용문제였던 것 같다.

인접한 지역과의 차가 L이상 R 이하인 영역을 벡터에 담고,

담긴 벡터들 값의 평균을 구해 이동된 다음 맵을 만드는 방법을 선택했다.


때문에 맵을 map[50][50][2]형태로 선언하였고,  두맵을 번갈아 가며 사용하게된다.


 방문배열은 매번 초기화 하는 비용을 없애고 싶어서 int형으로 선언하여 이동한 날짜수를 기록해주었다.


사실 인접한 지역을 구하면서 sum값을 구하면 더 효율적인 코드게 되겠지만, 결국 시간복잡도에서는 차이가 없을 것 같아 편하게 답을 구하는쪽으로 코딩했다.


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
#include <iostream>
#include <vector>
using namespace std;
 
struct _pair{
    int y;
    int x;
};
int N, L, R;
int map[50][50][2];
int visited[50][50];
int k;
int dy[] = {10-10};
int dx[] = {010-1};
int abs(int a){
    if(a < 0) a *= -1;
    return a;
}
void check(int y, int x, vector<_pair>& v){
    visited[y][x] = k;
 
    for(int i = 0 ; i < 4; i++){
        int ny = y + dy[i];
        int nx = x + dx[i];
        if(ny < 0 || ny >= N || nx < 0 || nx >= N || visited[ny][nx] >= k){
            continue;
        }
        int n = abs(map[y][x][k%2- map[ny][nx][k%2]);
        if(n >= L && n <= R){
            check(ny, nx, v);
            v.push_back({ny, nx});
        }
    }
}
int main(void){
    scanf("%d %d %d"&N, &L, &R);
    for(int i = 0 ; i < N; i++){
        for(int j = 0 ; j < N; j++){
            scanf("%d"&map[i][j][k]);
            visited[i][j] = -1;
        }
    }
 
    while(true){
        bool result = false;
        vector<_pair> v;
        for(int i = 0 ; i < N; i++){
            for(int j = 0 ; j < N; j++){
                if(visited[i][j] >= k) continue;
                check(i, j, v);
                int n = v.size();
                if(n > 0) result = true;
                int t_sum = map[i][j][k%2], t_cnt = 1 + n;
                for(int l = 0; l < n; l++){
                    int y = v[l].y;
                    int x = v[l].x;
                    t_sum += map[y][x][k%2];
                }
                int value = t_sum / t_cnt;
                for(int l = 0; l < n; l++){
                    int y = v[l].y;
                    int x = v[l].x;
                    map[y][x][(k + 1)%2= value;
                }
                map[i][j][(k + 1)%2= value;
                v.clear();
            }
        }
        if(!result) break;
        k++;
    }
 
 
    printf("%d", k);
 
}
cs


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

Visual Studio Code (VS Code) PS용 환경설정  (1) 2019.02.07
알고스팟 (algospot) FORTRESS  (1) 2019.01.26
백준(BOJ) 16236 - 아기 상어  (0) 2019.01.21
백준(BOJ) 16235 - 나무 재테크  (0) 2019.01.15
백준(BOJ) 1475 - 방번호  (0) 2019.01.02
블로그 이미지

짬뽕얼큰하게

,