한양대학교 ERICA 알고리즘 연구학회 영과일의 내부 대회 "ZOAC 2019"의 문제 출제 및 검수를 맡게 되었습니다.

 

그중 G번 문제인 변형 계단 수에 대한 풀이입니다.

 

목표

문제 화면 캡쳐

기존에 백준에 있던 계단 수 문제에 조건을 하나 추가시켜 변형시킨 문제다. 풀이 방법은 기존의 계단 수에서 새로운 조건을 추가시켜 주면 된다.

 

계단 수를 간략하게나마 풀이한다면 DP[계단 수 길이][마지막 자리 수]이다. 즉, ~~~~[0-9]의 끝 자리만 저장한 뒤 다음 DP에 더해 줄 때 끝자리±1의 끝 자리에 더해주면 되는 것이다.

  • DP[i][N] = DP[i-1][N-1] + DP[i-1][N+1]

변형 계단 수는 여기에 더해서 지금까지 얼마큼 연속으로 증가/감소했는지에 대한 정보를 추가적으로 갖고 있는다.

  • DP[변형 계단 수 길이][마지막 자리 수][현재까지의 증감]
    • 현재까지의 증감
      • 1(3-2)  : 연속 두 번 감소
      • 2(3-1)  : 연속 한 번 감소
      • 3        : 연속 증감 X
      • 4(3+1) : 연속 한 번 증가
      • 5(3+2) : 연속 두 번 증가

를 사용하여 DP식을 전개해 나가면 된다.

 

점화식은

  • DP[i][N][1] = DP[i-1][N+1][2]
  • DP[i][N][2] = DP[i-1][N+1][4] + DP[i-1][N+1][5]
  • DP[i][N][4] = DP[i-1][N-1][1] + DP[i-1][N-1][2]
  • DP[i][N][5] = DP[i-1][N-1][4]
  • 0일 경우는 ~1 -> ~10으로 가는 감소 밖에 없다. (예외 처리)
  • 9일 경우는 ~8 -> ~89로 가는 증가 밖에 없다. (예외 처리)

라고 볼 수 있다. 0과 9는 예외처리, 연속 증감 X의 경우에는 변형 계단 수의 길이가 1일 경우를 제외하고는 존재하지 않으므로 전처리를 제외하곤 신경 쓰지 않아도 된다.

 

마지막 정답은 DP[N]의 모든 배열들을 더해주면 된다.

 

이 문제의 시간 복잡도는 O(구하고자 하는 변형 계단 수의 길이) == O(N)이다.

 

코드


더보기
#include <stdio.h>
#define mod 1000000007

int dp[101][10][5]; // 0 == 3 dec, 1 == 2 dec, 2(mid) == 1 dec || inc, 3 == 2 inc, 4 == 3 inc

int main(){
    int N;
    int sum = 0;
    int mid = 2;
    scanf("%d", &N);
    for (int i = 0; i < 10; i++){ // 길이가 1이고 증감 X의 변형 계단 수의 개수는 1개
        dp[1][i][mid] = 1;
    }
    for(int i = 1; i < 9; i++){ // 길이가 2일 경우에는 연속 1번 증/감 밖에 없음
        dp[2][i][mid+1] = dp[1][i-1][mid];
        dp[2][i][mid-1] = dp[1][i+1][mid];
    }
    dp[2][0][mid-1] = dp[1][1][mid]; // 0 예외처리
    dp[2][9][mid+1] = dp[1][8][mid]; // 9 예외처리
    for (int i = 3; i <= N; i++){
        for (int j = 0; j < 10; j++){
            if (j == 0){ // 0 예외처리 0일 경우는 1 -> 10으로 가는 감소 밖에 없다.
                dp[i][0][mid-1] = dp[i-1][1][mid+1] % mod;
                dp[i][0][mid-2] = dp[i-1][1][mid-1] % mod;
            }
            else if (j == 9) { // 9 예외처리 9일 경우는 8 -> 89로 가는 증가 밖에 없다.
                dp[i][9][mid+1] = dp[i-1][8][mid-1] % mod;
                dp[i][9][mid+2] = dp[i-1][8][mid+1] % mod;
            }
            else { // 점화식
                dp[i][j][mid+1] = (dp[i-1][j-1][mid-1] + dp[i-1][j-1][mid-2]) % mod;
                dp[i][j][mid+2] = dp[i-1][j-1][mid+1] % mod;
                dp[i][j][mid-1] = (dp[i-1][j+1][mid+1] + dp[i-1][j+1][mid+2]) % mod;
                dp[i][j][mid-2] = dp[i-1][j+1][mid-1] % mod;
            }
        }
    }
    for (int i = 0; i < 10; i++){ // 정답 N의 모든 배열을 더해준다.
        for (int j = 0; j < 5; j++){
            sum += dp[N][i][j];
            sum %= mod;
        }
    }
    printf("%d\n", sum % mod);
    
}

 

한양대학교 ERICA 알고리즘 연구학회 영과일의 내부 대회 "ZOAC 2019"의 문제 출제 및 검수를 맡게 되었습니다.

 

그중 F번 문제인 Small World Network에 대한 풀이입니다.

 

 

 

목표

문제 화면 캡쳐

2019-2학기 김태형교수님의 "소셜 네트워크 분석"이라는 수업을 들으면서 배웠던 내용을 문제로 만들어 보았습니다. Small World Network란 이론에서 실제 실험 값의 평균이 6에 수렴하더라 라는 수업 내용을 듣고 친구 관계 네트워크가 주어졌을 때 이 네트워크가 Small World Network가 만족하는지 확인하는 문제입니다.

 

이 문제를 해결하기 위한 조건은 이렇습니다.

  • 모든 노드들에 대해서 한 노드에서 어떤 노드로 가는 방법이 6단계 이하여야 한다.

즉 1~N까지 모든 노드들을 탐색하면서 해당 노드와 다른 모든 노드들이 6단계 이하로 연결되어 있어야 한다는 것입니다.

 

저는 이 문제를 BFS를 통해 해결하였지만 플로이드-워샬 알고리즘을 통해서도 해결할 수 있습니다.

 

이 문제의 시간 복잡도는 O(모든 노드(N) * BFS(N)) == O(N2) 입니다.

 

코드

더보기

C++

#include <bits/stdc++.h>

using namespace std;

vector <vector<int> > node(101); // 노드의 개수

int chk[101];

void bfs(int n){ // BFS 따로 BFS에 대해선 설명하지 않겠습니다.
    int fn;
    queue <int> q;
    chk[n] = 0;
    q.push(n);
    while(!q.empty()){
        fn = q.front();
        q.pop();
        for(int i = 0; i < node[fn].size(); i++){
            if(chk[node[fn][i]] == -1){
                q.push(node[fn][i]);
                chk[node[fn][i]] = chk[fn] + 1;
            }
        }
    }
}

int main(){
    int N, K; cin >> N >> K;
    for(int i = 0; i < K; i++){ // 친구관계 형성
        int a, b; scanf("%d%d", &a, &b);
        node[a].push_back(b);
        node[b].push_back(a);
    }
    for(int i = 1; i <= N; i++){
        memset(chk, -1, sizeof(chk)); // 노드를 탐색할 때 마다 노드 초기화
        bfs(i); // BFS
        for(int j = 1; j <= N; j++){
            if(chk[j] == -1 || chk[j] > 6){ // 노드가 이어져있지 않거나, 6보다 많은 단계로 연결되어 있으면
                printf("Big World!\n");
                return 0;
            }
        }
    }
    printf("Small World!\n");
}

 

한양대학교 ERICA 알고리즘 연구학회 영과일의 내부 대회 "ZOAC 2019"의 문제 출제 및 검수를 맡게 되었습니다.

 

그중 A번 문제인 ZOAC 2에 대한 풀이입니다.

 

목표

ZOAC 2 문제 캡처

문제를 보시면 아시다 싶이 알파벳이 순서대로 써져 있는 원판을 돌리면서 원하는 문장열을 순서대로 가장 빠르게 출력하는데 걸리는 시간을 구하는 문제입니다.

 

먼저, 원판을 돌릴 수 있는 방법이 2가지라는 것을 알 수 있습니다. 한번 돌리기 시작하면 한쪽으로만 돌려야 하기에 (ex. 왼쪽으로 돌렸으면 다음 문자까지 왼쪽으로만 돌려야 한다.) 다음 문자열까지 왼쪽으로만 혹은 오른쪽으로만 돌려야 합니다. 이 돌리는 횟수를 A: 1(27) ~ Z: 26(52)까지 두고 현재 문자에서 다음 문자까지의 거리라고 한다면 거리는 다음과 같이 표현될 수 있습니다.

  • abs(다음 문자 - 현재 문자)
  • 26 - abs(다음 문자 - 현재 문자)

또는

  • 다음 문자 - 현재 문자 (음수이면 +26) 
  • 현재 문자 - 다음 문자 (음수이면 +26)

그러므로 해당 2개의 값 중에서 최소 값만 뽑아내어 모든 문자열을 탐색하면 되는 문제입니다.

 

모든 문자열을 탐색하므로 문제의 시간 복잡도는 O(문자열의 길이) == O(N)입니다.

 

코드

더보기

Python3 (두 번째 방법)

input = input()

ans = min(abs(ord('A') + 26 - ord(input[0])), ord(input[0]) - ord('A')) # 처음 화살표는 'A'를 가리킨다.
for i in range(len(input)-1) :
	# abs 처리
    left = ord(input[i]) - ord(input[i+1])
    right = ord(input[i+1]) - ord(input[i])
    if left < 0:
        left += 26
    if right < 0:
        right += 26
    ans += min(abs(left), abs(right))
print(ans)

C++ (첫 번째 방법)

#include <bits/stdc++.h>

using namespace std;

int main(){
	string inp;
	cin >> inp;
    int ans = 0;
    inp = 'A' + inp; // 처음 화살표는 'A'를 가리킨다.
    for(int i = 0; i < inp.size()-1; i++){
    	ans += min(abs((inp[i+1] - 'A') - (inp[i] - 'A')), 26 - abs((inp[i+1] - 'A') - (inp[i] - 'A')));
        // 왼쪽, 오른쪽중 최솟값을 더함
    }
    cout << ans << '\n';
    return 0;
}

 



목표



코드


Stack

import java.util.Scanner;

public class LinkedStack<Integer> {

private static SinglyLinkedList<java.lang.Integer> list = new SinglyLinkedList<>(); // an empty list
public LinkedStack() { } // new stack relies on the initially empty list
public static int size() { return list.size(); }
public static boolean isEmpty() { return list.isEmpty(); }
public static void push(java.lang.Integer element) { list.addFirst(element); }
public static java.lang.Integer top() { return list.first(); }
public static java.lang.Integer pop() { return list.removeFirst(); }

public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("-----------------------------------");
System.out.println("0 = End, 1 = Push, 2 = Pop, 3 = Top");
System.out.println("-----------------------------------");
System.out.print("Case : ");
int Case = sc.nextInt();
if (Case == 0) {
System.out.println("Program is End!");
break;
}
else if (Case == 1) {
System.out.print("Element : ");
int tmpi = sc.nextInt();
java.lang.Integer ele = tmpi;
push(ele);
}
else if (Case == 2) {
if(isEmpty()) System.out.println("No element in Stack");
else System.out.println(pop());
}
else {
if(isEmpty()) System.out.println("No element in Stack");
else System.out.println(top());
}
}
sc.close();


}
}


Queue

import java.util.Scanner;

public class LinkedQueue<Integer> {
private static SinglyLinkedList<java.lang.Integer> list = new SinglyLinkedList<>();

public static int size() {
return list.size();
}

public static boolean isEmpty() {
return list.isEmpty();
}

public static void enqueue(java.lang.Integer element) {
list.addLast(element);
}

public static java.lang.Integer first() {
return list.first();
}

public static java.lang.Integer dequeue() {
return list.removeFirst();
}

public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("--------------------------------------------");
System.out.println("0 = End, 1 = Enqueue, 2 = Dequeue, 3 = First");
System.out.println("--------------------------------------------");
System.out.print("Case : ");
int Case = sc.nextInt();
if (Case == 0) {
System.out.println("Program is End!");
break;
} else if (Case == 1) {
System.out.print("Element : ");
int tmpi = sc.nextInt();
java.lang.Integer ele = tmpi;
enqueue(ele);
} else if (Case == 2) {
if (isEmpty()) System.out.println("No element in Queue");
else System.out.println(dequeue());
} else {
if (isEmpty()) System.out.println("No element in Queue");
else System.out.println(first());
}
}
sc.close();
}
}



실행화면




파일


LinkedQueue.java

LinkedStack.java