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




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
#pragma warning(disable :4996)
#include<iostream>
#include<string>
using namespace std;
 
int alp[26];
int main(void) {
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    string str;
    cin >> str;
    
    for (int i = 0; i < str.length(); i++) {
        if (str[i] >= 'a' && str[i] <= 'z')
            alp[str[i] - 'a']++;
        else
            alp[str[i] - 'A']++;
    }
    
    int Max = 0, idx =0;
    for (int i = 0; i < 26; i++) {
        if (Max < alp[i]) {
            idx = i;
            Max = alp[i];
        }
    }
    
    for (int i = 0; i < 26; i++) {
        if (alp[i] == Max && i != idx) {
            cout << "?";
            return 0;
        }
    }
 
    char ans = idx + 'A';
    cout << ans;
    return 0;
}
 
cs


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


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
#pragma warning(disable :4996)
#include<iostream>
#include<string>
using namespace std;
int alp[26];
int main(void) {
    //ios::sync_with_stdio(false);
    cin.tie(0);
    
    string str;
    cin >> str;
 
    for (int i = 0; i < 26; i++)
        alp[i] = -1;
    for (int i = 0; i < str.length(); i++) {
        if (alp[str[i] - 'a'== -1)
            alp[str[i] - 'a'= i;
    }
    for (int i = 0; i < 26; i++)
        if (alp[i] >= 0cout << alp[i] << ' ';
        else
            cout << -1 << ' ';
 
    return 0;
}
 
cs


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


가령 1--2--3--4 


이러한 연결 관계를 가지는 그래프가 주어지면, 1을 빨간색, 2를 초록색으로 칠하고, 다시 3을 빨간색 4를 초록색


이렇게 두 가지의 색을 이용하여, 그래프의 모든 노드를 인접한 노드의 삭과 다른 색으로 색칠 할 수 있는지


검증하는 문제이다.



색깔의 구현은, 방문 처리 배열의 값을 1과 2사이에서 토글되게 하였다. 0이면 방문하지 않은것



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
#pragma warning(disable :4996)
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
 
vector<int> grp[20001];
 
int vis[20001]; //초기 0, 두종류 1,2 -> 인접한 정점간에 다른 vis 값을 가지면 이분그래프
int vCnt, eCnt;
bool isBigrp = true;
queue<int> q;
void bfs(int st) {
    q.push(st);
    vis[st] = 1;
    while (!q.empty()) {
        int cur = q.front();
        q.pop();
        for (int i = 0; i < grp[cur].size(); i++) {
            
            int next = grp[cur][i]; //확인할 지점
            
            if (vis[next] != 0 && vis[cur] == vis[next]) { //인접한 정점과 같은 vis값을 가지는 경우
                cout << "NO\n";
                isBigrp = false;
                return;
            }
            if (vis[next] > 0continue//재방문 못하게
            q.push(next);
            vis[next] = vis[cur] % 2 + 1//cur이 1이면 next는 2가되고, vice versa
            
        }
    }
    
}
int main(void) {
    ios::sync_with_stdio(false);
    cin.tie(0);
    int T;
    cin >> T;
    while (T--) {
        cin >> vCnt >> eCnt;
        for (int i = 0; i < eCnt; i++) {
            int src, dst;
            cin >> src >> dst;
            grp[src].push_back(dst);
            grp[dst].push_back(src);
        }
        
        for (int i = 1; i <= vCnt; i++) {
            if (vis[i] == 0) {
                bfs(i);
                if (!isBigrp) break// 이분그래프가 아니라는 결론이 났으면 더 진행할 필요가 없다
            }
        }
        if(isBigrp)
            cout << "YES\n";
 
        //이 아래로는 초기화 부분
        while (!q.empty()) q.pop();
        for (int i = 1; i <= vCnt; i++) {
            vis[i] = 0;
            grp[i].clear();
        }
        isBigrp = true;
    }
    return 0;
}
 
cs


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


정점별로 연걸된 나머지 정점까지의 거리의 합을 구하고, 그 합의 최솟값을 가지는 정점의 번호를 출력해주면 된다.



인접행렬을 만들 때, 방향성이 없는 그래프라는 것을 주의하자.



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
#pragma warning(disable :4996)
#include<iostream>
#include<queue>
using namespace std;
 
int grp[101][101]; // 1-indexed
int n, m; //유저수, 관계수
int dis[101]; //방문처리 + 거리
queue<int> q;
 
void bfs(int st) {
    q.push(st);
    dis[st]++;
    while (!q.empty()) {
        int qs = q.size();
        while (qs--) {
            int cur = q.front();
            q.pop();
            for (int i = 1; i <= n; i++) {
                if (grp[cur][i] != 1 || dis[i] >= 0continue;
                q.push(i);
                dis[i] = dis[cur] + 1;
            }
        }
    }
}
 
int main(void) {
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    cin >> n >> m;
    for (int i = 0; i < m; i++) {
        int src, dst;
        cin >> src >> dst;
        grp[src][dst] = 1;
        grp[dst][src] = 1//무방향성
    }
 
    int Min = 100000000, ans;
    for (int i = 1; i <= n; i++) {
        for (int i = 1; i <= n; i++//방문처리 배열 초기화
            dis[i] = -1;
        bfs(i);
        int Sum = 0;
        for (int i = 1; i <= n; i++)
            Sum += dis[i];
        if (Sum < Min) {
            Min = Sum;
            ans = i;
        }
    }
    cout << ans;
    
    return 0;
}
 
cs


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


특정 노드 사이의 촌수를 계산해주면 된다.



주어지는 정보들을 그래프로 표현해보면, 결국 촌수는 정점과 정점사이의 최단거리이다.



따라서 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
46
47
48
49
50
51
52
53
54
55
#pragma warning(disable :4996)
#include<iostream>
#include<queue>
using namespace std;
 
int grp[101][101]; //1-indexed
int vis[101]; //양수면 방문한 것
queue<int> q;
 
int n, st, en, m; //n명의 사람, m개의 관계
 
void bfs() {
    q.push(st);
    vis[st]++;
    
    while (!q.empty()) {
        int qs = q.size();
        while (qs--) {
            int cur = q.front();
            q.pop();
            for (int i = 1; i <= n; i++) {
                if (grp[cur][i] != 1 || vis[i] >= 0continue;
                
                q.push(i);
                vis[i] = vis[cur] + 1;
                if (i == en) { //종료 조건
                    cout << vis[i];
                    return;
                }
            }
        }
    }
    cout << -1// 연결이 되지 않은 것
}
 
int main(void) {
 
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> n >> st >> en >> m;
    for (int i = 1; i <= m; i++) {
        int src, dst;
        cin >> src >> dst;
        grp[src][dst] = 1;
        grp[dst][src] = 1//무방향성
    }
 
    for (int i = 1; i <= n; i++)
        vis[i] = -1//양수면 방문한 것으로 처리
 
    bfs();
 
    return 0;
}
 
cs


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



DFS를 활용해서 연결 요소의 개수를 파악해준다. 연결된 클러스터의 개수를 파악하는 문제라고 생각하면 된다.


DFS가 몇번 실행되는지 파악해주면되고, 무방향 그래프라는 것을 인지하고 인접행렬의 형태로 입력을 받아준다.



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
#pragma warning(disable :4996)
#include<iostream>
using namespace std;
 
int grp[1001][1001], n, m; //1-indexed
bool vis[1001];
 
void dfs(int cur) {
    for (int i = 1; i <= n; i++) {
        if (grp[cur][i] == 1 && !vis[i]) {
            vis[i] = true;
            dfs(i);
        }
    }
}
int main(void) {
    ios::sync_with_stdio(false);
    cin.tie(0);
 
    cin >> n >> m;
 
    for (int i = 1; i <= m; i++) {
        int src, dst;
        cin >> src >> dst;
        grp[src][dst] = 1;
        grp[dst][src] = 1//방향이 없으므로
    }
 
    int ret = 0;
    for (int i = 1; i <= n; i++) {
        if (!vis[i]) {
            //printf("%d에서 실행\n", i);
            vis[i] = true;
            dfs(i);
            ret++//dfs의 실행 횟수가 곧 연결 요소의 수
        }
    }
 
    cout << ret;
    return 0;
}
 
cs


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



모든 점을 방문할 수 있는지 확인하면 되는 문제이므로 bfs / dfs로 기본적으로 접근할 수 있다.


또한 n이 작기 때문에 플로이드 와샬도 가능하다. 가중치는 모두 1로 두면 되겠다.




이러한 문제를 풀 때 신경써줄 부분은, 자기 자신을 곧바로 방문할 수 있는지 확인하는 것이다.


이 문제에서는 노드1->노드1 이런식으로 곧바로 자기 자신을 방문할 수 없고, 1->2->3->1 이런식으로 사이클을 거쳐서 root(자기 자신)을 방문할 수 있다.


따라서 플로이드 와샬 알고리즘을 적용할 때, 비용을 무한대로 초기화 하는 과정에서, 자기 자신으로 가는 비용도 무한대로 초기화해주고 시작해야 한다.




비슷한 맥락으로, DFS로 문제를 풀이할 때, 보통 시작점을 방문처리하고 알고리즘을 시작한다.


하지만 시작점을 방문처리하고, 미방문한 지점을 이어서 방문하도록 알고리즘을 구현하면


1-> 2-> 3-> 1  이 과정에서, 마지막에 3->1을 방문할 수가 없다. 초기에 시작 지점인 1을 방문처리 했기 때문이다.


따라서 이것을 방지하기 위해서 시작지점을 방문처리하지 않는다. 3->1을 거쳐서 시작 지점에서 다시 for 문을 돌면 어짜피 갈 수 있는 곳이 없으므로 재귀를 탈출하게 된다.




1. DFS


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
#pragma warning(disable :4996)
#include<iostream>
using namespace std;
 
int m[101][101];
bool vis[101][101], chk[11];
int n, root;
void dfs(int cur) {
 
    for (int i = 0; i < n; i++) {
        if (m[cur][i] == 1 && !chk[i]) {
            chk[i] = true;
            dfs(i);
        }
    }
}
 
int main(void) {
    ios::sync_with_stdio(false);
    cin.tie(0);
 
    cin >> n;
 
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            cin >> m[i][j];
    //cout << '\n';
 
    for (int i = 0; i < n; i++) {
        dfs(i); // i->i로 곧바로 갈 수 없으므로 시작점 방문처리 안 함
 
        //노드i에서 시작해서 방문할 수 있는 점들 표시
        for (int j = 0; j < n; j++) {
            if (chk[j]) cout << 1 << ' ';
            else cout << 0 << ' ';
        }
        cout << '\n';
 
        //초기화
        for (int i = 0; i < n; i++
            chk[i] = false;
        
    }
 
    return 0;
}
 
cs




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
#include<iostream>
#include<algorithm>
#define INF 100000
using namespace std;
 
int n; //정점 개수
int m[101][101];
 
void FW() { //플로이드 와샬
    for (int k = 0; k < n; k++)
        for (int j = 0; j < n; j++)
            for (int i = 0; i < n; i++)
                m[i][j] = min(m[i][j], m[i][k] + m[k][j]);
}
int main(void) {
 
    cin >> n;
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++) {
        
            cin >> m[i][j];
            if (m[i][j] == 0 ) m[i][j] = INF;
            //자기 자신으로 갈 수 없다고 봄 -> 자기 자신으로 가는 비용도 무한초기화
        }
    
    FW();
 
    //cout << '\n';
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            if (m[i][j] == INF) //비용이 무한 -> 방문할 수 없다는 의미
                cout << 0 << ' ';
            else
                cout << 1 << ' ';
        }
        cout << '\n';
    }
    
    
    return 0;
}
cs


https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV7GOPPaAeMDFAXB&categoryId=AV7GOPPaAeMDFAXB&categoryType=CODE



모든 정점을 시작점으로 dfs를 돌려주면 된다.



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
#include<iostream>
 
using namespace std;
 
int grp[11][11]; //1-indexed
bool vis[11]; //방문처리
int n, m, Max = 1;
 
void dfs(int len, int cur) {
    vis[cur] = true;
 
    if (Max < len) Max = len;
    for (int i = 1; i <= n; i++) {
        if (grp[cur][i] == 1 && !vis[i])
            dfs(len + 1, i);
    }
    vis[cur] = false;
}
 
void initGrp() {
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            grp[i][j] = 0;
}
 
int main(void) {
 
    int T;
    cin >> T;
    for (int tc = 1; tc <= T; tc++) {
        
        cin >> n >> m;
        
        for (int i = 0; i < m; i++) {
            int src, dst;
            cin >> src >> dst;
            
            grp[src][dst] = 1;
            grp[dst][src] = 1;
            
        }
 
        for (int i = 1; i <= n; i++
            dfs(1, i); // i번 정점에서 길이 
        
        printf("#%d %d\n", tc, Max);
        Max = 1;
        initGrp();
    }
 
    return 0;
}
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
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
#include<iostream>
 
using namespace std;
 
int grp[11][11]; //1-indexed
bool vis[11]; //방문처리
int n, m, Max = 1;
 
void dfs(int len, int cur) {
    //vis[cur] = true;
 
    if (Max < len) Max = len;
    for (int i = 1; i <= n; i++) {
        if (grp[cur][i] == 1 && !vis[i]) {
            vis[i] = true;
            dfs(len + 1, i);
            vis[i] = false;
        }
    }
    //vis[cur] = false; //확인이 끝난 점은 방문을 해제
}
 
void initGrp() {
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            grp[i][j] = 0;
}
 
int main(void) {
 
    int T;
    cin >> T;
    for (int tc = 1; tc <= T; tc++) {
        
        cin >> n >> m;
        
        for (int i = 0; i < m; i++) {
            int src, dst;
            cin >> src >> dst;
            
            grp[src][dst] = 1;
            grp[dst][src] = 1;
            
        }
 
        for (int i = 1; i <= n; i++) {
            vis[i] = true;
            dfs(1, i); // i번 정점에서 길이
            vis[i] = false;
        }
        
        printf("#%d %d\n", tc, Max);
        Max = 1;
        initGrp();
    }
 
    return 0;
}
cs


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


공백을 포함한 문자열을 받을 때는



getline(cin, string변수);


이와 같이 사용한다. 다만 이를 다른 입력과 함께 사용할 경우 버퍼에 개행이 포함되어 개행이 누락되는 경우가 있기 때문에 조심해야 한다. 이 문제의 경우에는 입력을 한 번만 받기 때문에 상관이 없었지만, 조심해야 한다.




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
#include<iostream>
#include<string>
using namespace std;
 
int main(void) {
    char chr[1000001];
    //cin >> str;
    string str;
    getline(cin, str);
 
 
    int cnt = 0;
    bool findOne = false, findSpace = false;
    //첫번째 단어를 찾았는지, 현재 공백이 등장한 상태인지
 
    for (int i = 0; i < str.length(); i++) {
        if (!findOne && str[i] != ' ') {
            findOne = true;
            cnt++;
            continue;
        }
        else if(findOne) {
            if (str[i] == ' ') findSpace = true;
            else {
                if (findSpace) {
                    cnt++;
                    findSpace = false;
                }
            }
        }
    
    }
    cout << cnt << '\n';
    return 0;
}
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <string>
#include <vector>
#include<iostream>
 
using namespace std;
int val, opr[2= {1,0}; //+, -
int arr[20], ret = 0;
void btk(int k, vector<int> &nums, int tar) {
    if (k == val) {
        int Sum = 0;
        for (int i = 0; i < k; i++) {
            if (i == 0) { //첫 숫자 부호
                if (arr[0== 1)
                    Sum = nums[0];
                else
                    Sum = nums[0* -1;
            }
            else { //나머지 연산자
                if (arr[i] == 1)
                    Sum += nums[i];
                else
                    Sum -= nums[i];
            }
        }
        if (Sum == tar) ret++;
        return;
    }
    
    for (int i = 0; i < 2; i++) {
        arr[k] = opr[i];
        btk(k + 1, nums, tar);
    }
}
int solution(vector<int> nums, int tar) {
    val = nums.size();
    btk(0, nums, tar);
    return ret;
}
 
int main(void) {
    solution({ 1,1,1,1,1 }, 3);
    return 0;
}
cs


+ Recent posts