안녕하세요
문제해결기법
9b_multiplicationGame
12141629 채민균
1. 문제분석
2. 문제풀이 아이디어
3. 소스코드
4. 결과 및 분석
1. 문제분석
- 숫자들이 적혀있는 m행 n열의 말판이 주어진다.
- 두 사람(A,B)이 똑같은 HP 를 가지며, 동일한 시작 위치에서 게임을 시작한다.
- 하나의 말판을 가지고 K 번 게임을 진행한다.
- 두 사람 모두 L 개의 카드 덱을 갖고 있으며, 각자의 카드 덱 내에는 같은 숫자의 카드가 존재할 수 있다.
- 항상 사람 A 먼저 게임을 시작한다.
- 각자의 카드 덱에서 위에서 두 장을 뽑은 뒤 곱하고, 곱한 값이 적혀있는 말판까지 상대방 말을 이동하는데, 이동한 맨하탄 거리만큼을 상대방 HP 에서 차감한다.
- 사용한 카드 두 장은 순서대로 맨 아래에 집어넣는다.
- HP 가 0 이하가 되는 사람이 패배자가 되며, 승리자의 알파벳을 출력한다.
1. 문제분석
- 숫자들이 적혀있는 m행 n열의 말판이 주어진다.
- 두 사람(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