안녕하세요

문제해결기법

9b_multiplicationGame

12141629 채민균

1. 문제분석

2. 문제풀이 아이디어

3. 소스코드

4. 결과 및 분석

1. 문제분석

- 숫자들이 적혀있는 m행 n열의 말판이 주어진다.

- 두 사람(A,B)이 똑같은 HP 를 가지며, 동일한 시작 위치에서 게임을 시작한다.

- 하나의 말판을 가지고 K 번 게임을 진행한다.

-  두 사람 모두 L 개의 카드 덱을 갖고 있으며, 각자의 카드 덱 내에는 같은 숫자의 카드가 존재할 수 있다.

- 항상 사람 A 먼저 게임을 시작한다.

- 각자의 카드 덱에서 위에서 두 장을 뽑은 뒤 곱하고, 곱한 값이 적혀있는 말판까지 상대방 말을 이동하는데, 이동한 맨하탄 거리만큼을 상대방 HP 에서 차감한다.

- 사용한 카드 두 장은 순서대로 맨 아래에 집어넣는다.

- HP 가 0 이하가 되는 사람이 패배자가 되며, 승리자의 알파벳을 출력한다.

1. 문제분석

- 숫자들이 적혀있는 mn열의 말판이 주어진다.

- 두 사람(A,B)이 똑같은 HP 를 가지며, 동일한 시작 위치에서 게임을 시작한다.

- 하나의 말판을 가지고 K 번 게임을 진행한다.

-  두 사람 모두 L 개의 카드 덱을 갖고 있으며, 각자의 카드 덱 내에는 같은 숫자의 카드가 존재할 수 있다.

- 항상 사람 A 먼저 게임을 시작한다.

- 각자의 카드 덱에서 위에서 두 장을 뽑은 뒤 곱하고, 곱한 값이 적혀있는 말판까지 상대방 말을 이동하는데, 이동한 맨하탄 거리만큼을 상대방 HP 에서 차감한다.

- 사용한 카드 두 장은 순서대로 맨 아래에 집어넣는다.

- HP 가 0 이하가 되는 사람이 패배자가 되며, 승리자의 알파벳을 출력한다.

2. 문제풀이 아이디어(사고의 과정)

- 문제의 조건

(0 < T <= 5), (0 < M,N <= 2500), (0 < K <= 5000), (0 < L <= 1000), (카드에 적힌 각 카드의 수 <= 2500), (초기 HP 값 <= 100000)

- 항상 사람 A 먼저 게임을 시작한다.

- 각자의 카드 덱에서 위에서 두 장을 뽑은 뒤 곱하고, 곱한 값이 적혀있는 말판까지 상대방 말을 이동하는데, 이동한 맨하탄 거리만큼을 상대방 HP 에서 차감한다.

- 사용한 카드 두 장은 순서대로 맨 아래에 집어넣는다.

- HP 가 0 이하가 되는 사람이 패배자가 되며, 승리자의 알파벳을 출력한다.

2. 문제풀이 아이디어(사고의 과정)

 

 

 

​=>A.탐색연산이 빠르면 좋겠구나!

 

 

 

2. 문제풀이 아이디어(사고의 과정)

Q1.무엇을 탐색 해야하지?

A1.카드의 덱 맨 위의 숫자 2개의 곱이 적혀있는 말판의 위치

 

Q2.어떻게 하면 탐색연산을 빠르게 하지?

A2.

- 말판에 적혀 있는 숫자, 행좌표, 열좌표를 담고 있는 구조체를 만들고,

- 1차원 구조체벡터에 입력값들을 넣고,

- 말판에 적혀 있는 숫자를 기준으로 정렬하면,

- 이진탐색을 사용할 수 있겠구나.

3. 소스코드(구조)

struct player {
    int hp; // 각 player 의 남은 체력
    int i; // player 가 위치한 행좌표
    int j; // player 가 위치한 열좌표
};

struct cell {
    int value; // 말판에 적힌 숫자
    int i; // 말판의 행좌표
    int j; // 말판의 열좌표
};

3. 소스코드(기본입력)

bool cmp(cell a, cell b) {
    return a.value < b.value;
}

vector<cell> cellV;
int m, n, num, k;
cin >> m >> n;

for (int i = 0; i < m; i++) {
    for (int j = 0; j < n; j++) {
        cin >> num;
        // 말판에 적힌 수, 행좌표, 열좌표 순서대로 입력
        cell c = {num, i, j}; 
        cellV.push_back(c); // 1차원 말판 벡터에 삽입
    }
}
// 말판에 적힌 수 기준으로 정렬
sort(cellV.begin(), cellV.end(), cmp); 

3. 소스코드(기본입력)

cin >> k;
// 하나의 말판으로 k 번 게임진행
while (k--) {//start while문(k--)
    int l, healthPoint, x, y, dummy;
    cin >> l;
    vector<int> deck_of_a; // A 플레이어의 카드덱
    vector<int> deck_of_b; // B 플레이어의 카드덱
    for (size_t i = 0; i < l; i++) {
        cin >> dummy;
        deck_of_a.push_back(dummy);
    }
    for (size_t i = 0; i < l; i++) {
        cin >> dummy;
        deck_of_b.push_back(dummy);
    }
    cin >> healthPoint >> x >> y;
    player A = {healthPoint, x, y}; // A 플레이어 정보
    player B = {healthPoint, x, y}; // B 플레이어 정보

3. 소스코드(게임시작)

bool turn = true; //A 차례부터 시작!
int index = 0, next; // index == 곱셈할 첫 번째 수, next == 곱셈할 두 번째 수
while (true) {
    if (turn) { //A 차례
        next = (index + 1) % l; // next 세팅
        cell p = findValue(0, m * n - 1, deck_of_a[index] * deck_of_a[next]); // 말판 이진탐색
        B.hp = B.hp - (abs(B.i - p.i) + abs(B.j - p.j)); // 이동한 맨하탄 거리만큼 hp에서 차감
        if (B.hp <= 0) { 
            cout << "A\n"; // B의 hp가 0 이하이므로 A 가 WINNER
            break; // 게임 종료
        }
        B.i = p.i;
        B.j = p.j;
        turn = false; // B 차례로 바꿔줌
    } else {
        cell p = findValue(0, m * n - 1, deck_of_b[index] * deck_of_b[next]); // 말판 이진탐색
        A.hp = A.hp - (abs(A.i - p.i) + abs(A.j - p.j)); // 이동한 맨하탄 거리만큼 hp에서 차감
        if (A.hp <= 0) { //B 차례
            cout << "B\n"; // A의 hp가 0 이하이므로 B 가 WINNER
            break; // 게임 종료
        }
        A.i = p.i;
        A.j = p.j;
        index = (index + 2) % l; // 두 개의 숫자를 사용했으니, 그 다음 두 개의 사용하기 위해 세팅
        turn = true; // A 차례로 바꿔줌
    }
}
}//end while문(k--)

3. 소스코드(이진탐색)

cell p = findValue(0, m * n - 1, deck_of_a[index] * deck_of_a[next]);
cell p = findValue(0, m * n - 1, deck_of_b[index] * deck_of_b[next]);
        
cell findValue(int low, int high, int value) {
    int mid = (low + high) / 2;
    if (cellV[mid].value < value) {
        return findValue(mid + 1, high, value);
    } else if (cellV[mid].value > value) {
        return findValue(low, mid - 1, value);
    } else {
        return cellV[mid];
    }
}

3. 소스코드(전체코드)

//일반 구현 문제

#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>

using namespace std;

struct player {
    int hp;
    int i;
    int j;
};

struct cell {
    int value;
    int i;
    int j;
};

bool cmp(cell a, cell b) {
    return a.value < b.value;
}

vector<cell> cellV;

cell findValue(int low, int high, int value) {
    int mid = (low + high) / 2;
    if (cellV[mid].value < value) {
        return findValue(mid + 1, high, value);
    } else if (cellV[mid].value > value) {
        return findValue(low, mid - 1, value);
    } else {
        return cellV[mid];
    }
}

int main() {
    std::ios::sync_with_stdio(false);
    int t;
    cin >> t;
    while (t--) {
        int m, n, num, k;
        cin >> m >> n;

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                cin >> num;
                cell c = {num, i, j};
                cellV.push_back(c);
            }
        }
        sort(cellV.begin(), cellV.end(), cmp);
        cin >> k;
        while (k--) {//start while문
            int l, healthPoint, x, y, dummy;
            cin >> l;
            vector<int> deck_of_a;
            vector<int> deck_of_b;
            for (size_t i = 0; i < l; i++) {
                cin >> dummy;
                deck_of_a.push_back(dummy);
            }
            for (size_t i = 0; i < l; i++) {
                cin >> dummy;
                deck_of_b.push_back(dummy);
            }
            cin >> healthPoint >> x >> y;
            player A = {healthPoint, x, y};
            player B = {healthPoint, x, y};
            bool turn = true;//A 차례
            int index = 0, next;
            while (true) {
                if (turn) {
                    next = (index + 1) % l;
                    cell p = findValue(0, m * n - 1, deck_of_a[index] * deck_of_a[next]);
                    B.hp = B.hp - (abs(B.i - p.i) + abs(B.j - p.j));
                    if (B.hp <= 0) {
                        cout << "A\n";
                        break;
                    }
                    B.i = p.i;
                    B.j = p.j;
                    turn = false;
                } else {
                    cell p = findValue(0, m * n - 1, deck_of_b[index] * deck_of_b[next]);
                    A.hp = A.hp - (abs(A.i - p.i) + abs(A.j - p.j));
                    if (A.hp <= 0) {
                        cout << "B\n";
                        break;
                    }
                    A.i = p.i;
                    A.j = p.j;
                    index = (index + 2) % l;
                    turn = true;
                }
            }
        }//end while문
        cellV.clear();
    }
    return 0;
}

4. 결과 및 분석

 

# 분석

한 번의 테스트케이스 당 알고리즘의 시간 복잡도를 분석하면,

정렬 - MN*log(MN)

게임진행 - K*( ? log(MN) + 2L)

알고리즘 시간 복잡도 O( (MN+K)*log(MN) + KL )

 

# 결과

 Time used: 8.41 second

 Memory used: 101679104 bytes

감사합니다

문제해결기법 9주차 B번 문제 발표자료

By mingyun chae

문제해결기법 9주차 B번 문제 발표자료

2017년 5월 10일, 인하대학교 문제해결기법 발표자료 입니다.

  • 824