21609 상어중학교 > 2028KB, 0ms

  • DFS로 품
  • 푼 방법 
    • 블럭 찾고 (find_block())
      • DFS를 통해 블럭의 크기를 찾고 가장 큰 블럭과 비교해서 갱신한다.
      • 여기서 어이없게 틀렸는데 나는 블록이 2개 이상일 때만 찾는다고 하니까 블럭이 1개일 때만 고려했다. 블럭이 0개인걸 고려 안해서 39%에서 시간초과 났음
    • 터지고 (boom())
      • 찾은 블럭사이즈만큼 점수계산 후
      • DFS를 통해 해당 블럭 -2(빈칸)으로 바꿔줌.
      • 이때 DFS는 find_block()의 DFS와 같은 함수를 썼는데 flag를 이용해서 기능을 달리함
    • 중력 작용 (gravity())
      • 오른쪽 아래에서부터 위로 가는 방식. ↑↑↑↑ 이런 식
      • 내려야 하는 블럭 찾고 쭉 내림
      • 중력 작용 한 번에 해보려고 했는데 잘 안됐음
    • 90도 회전 (spin())
      • 90도 반시계 방향 회전 로직
      • map_temp에다가  map을 저장 후 90도 회전한 map_temp를 map에 다시 복사하는 방식
      • 반시계 방향 회전 로직은 [i][j]
    • 중력 작용 (gravity())

 

=> 중력작용, DFS, 회전 기출

#include <iostream>
#include <stack>
#include <iomanip>
#include <cstring>

#define MAX 20
using namespace std;

int N, M, map[MAX][MAX] = {};
int boom_x, boom_y, boom_size, boom_rainbow;
bool visited[MAX][MAX] = {};
int result = 0;

void input() {
	cin >> N >> M;
	for (int i = 0; i < N; i++)
		for (int j = 0; j < N; j++)
			cin >> map[i][j];
}

pair<int,int> DFS(int start_y, int start_x, int start_value, bool boom_flag) {
	bool visited_local[MAX][MAX] = {};
	int dy[4] = { -1,1,0,0 }, dx[4] = { 0,0,-1,1 };
	int block_cnt = 0, rainbow = 0;

	stack<pair<int, int>> s;
	s.push({ start_y, start_x });
	

	while (!s.empty()) {
		int y = s.top().first, x = s.top().second; s.pop();
		if (visited_local[y][x]) continue;
		visited_local[y][x] = true;
		if (boom_flag) map[y][x] = -2;
		if (map[y][x] != 0) visited[y][x] = true;
		else rainbow++;

		block_cnt++;

		for (int i = 0; i < 4; i++) {
			int new_y = y + dy[i], new_x = x + dx[i];
			if (new_y >= N || new_x >= N || new_y < 0 || new_x < 0 || map[new_y][new_x] < 0) continue;

			if ((!visited_local[new_y][new_x]) && (start_value == map[new_y][new_x] || map[new_y][new_x] == 0)) {
				s.push({ new_y, new_x });
			}
				
		}
	}

	//cout << endl << endl;

	return { block_cnt,rainbow };
}

bool find_block() {
	// 기준 블록 & 크기 & visited 초기화 
	boom_x = -1; boom_y = -1; boom_size = 0; boom_rainbow = 0;
	for (int i = 0; i < N; i++) memset(visited[i], false, N);

	// labeling & choose
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			if (map[i][j] <= 0 || visited[i][j]) continue;

			pair<int, int> DFS_result = DFS(i, j, map[i][j], false);

			if (DFS_result.first > boom_size) {
				boom_y = i; boom_x = j; boom_size = DFS_result.first; boom_rainbow = DFS_result.second;
			}
			else if (DFS_result.first == boom_size) {
				if (DFS_result.second > boom_rainbow) {
					boom_y = i; boom_x = j; boom_size = DFS_result.first; boom_rainbow = DFS_result.second;
				}
				else if (DFS_result.second == boom_rainbow) {
					if (i > boom_y) {
						boom_y = i; boom_x = j; boom_size = DFS_result.first; boom_rainbow = DFS_result.second;
					}
					else if (i == boom_y) {
						if (j > boom_x) {
							boom_y = i; boom_x = j; boom_size = DFS_result.first; boom_rainbow = DFS_result.second;
						}
					}
				}
				
			}
		}
	}

	// return
	if (boom_size <= 1) return false;
	return true;
}

void boom() {
	result += boom_size * boom_size;
	DFS(boom_y, boom_x, map[boom_y][boom_x], true);
}

void gravity() {
	for (int j = 0; j < N; j++) {
		for (int i = N - 1; i >= 0; i--) {
			if (map[i][j] < 0) continue;

			int next_i = i + 1; //, temp_i = i;
			
			while (next_i < N && map[next_i][j] == -2) next_i++;

			if (next_i - 1 != i) {
				map[next_i - 1][j] = map[i][j];
				map[i][j] = -2;
			}
		}
	}
}

void spin() {
	int map_temp[MAX][MAX] = {};
	for (int i = 0; i < N; i++)
		for (int j = 0; j < N; j++)
			map_temp[i][j] = map[i][j];

	for (int i = 0; i < N; i++)
		for (int j = 0; j < N; j++)
			map[i][j] = map_temp[j][N - 1 - i];
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);

	input();

	while (find_block()) {  // N^2 * DFS
		boom();				// DFS
		gravity();			// N^2 + a
		spin();				// 2N^2
		gravity();			// N^2 + a
	}

	cout << result;
}

'coding > baekjoon_codingstudy' 카테고리의 다른 글

20061 모노미노도미노2  (0) 2022.10.06
12100 2048(Easy)  (0) 2022.10.03
19238 스타트택시  (0) 2022.10.02
13460 구슬 탈출2  (0) 2022.10.02
14891 톱니바퀴 (골드 5)  (0) 2021.10.05

19238 스타트택시 > 2036KB, 584ms

메모리는 보통, 속도는 느린편 -> 사람 찾을 때 BFS 한 번만 하면 됨!

  • 간단한 로직
    • BFS 기본
    • 태울 사람이 남아있는지 체크하고 -> 고르고 -> 태우고
    • 태울 사람이 남아있는지 체크 : 태운 사람을 move_people로 저장하고 태울때마다 move_people++, move_people이 M(승객 수)와 같아지면 종료
    • 고르고 : queue에 담아둔 사람을 한명씩 bfs로 거리 체크함. 이때 태울 사람은 있지만 태우러 갈 수 없는 경우(사방이 벽)에는 flag를 써서 확인. 사람을 고르면 move_people++해주고 차량이동 및 연료 감소시킴
    • 태우고 : 고른 사람의 출발지와 목적지만 bfs하고 차량 옮기고 연료 빼주고 연료 남아있으면 연료 충전
  • 주의 사항 
    • 0차 : 종료 조건 고려안하고 로직 짬, 1차 : 연료만 고려하고 사람 고려 안함, 2차 : 모든 손님 이동 불가 고려 안함,
    • 4차 : 택시와 손님이 같은 곳에 서있을 때 고려 안함
    • y & x 주의하기!
#include <iostream>
#include <queue>

#define MAX 20
using namespace std;

typedef struct people {
	bool finish = false;
	int start_y;
	int start_x;
	int dest_y;
	int dest_x;
}PEOPLE;

typedef struct bfs_struct {
	int y, x, route = 0;
}BFS_STRUCT;

int N, M, map[MAX + 1][MAX + 1] = {};
long long int fuel;
int car_y, car_x;
PEOPLE pe_arr[MAX * MAX] = {};
int move_people = 0;

void input() {
	cin >> N >> M >> fuel;
	for (int i = 1; i <= N; i++)
		for (int j = 1; j <= N; j++)
			cin >> map[i][j];

	cin >> car_y >> car_x;

	for (int i = 0; i < M; i++)
		cin >> pe_arr[i].start_y >> pe_arr[i].start_x >> pe_arr[i].dest_y >> pe_arr[i].dest_x;	
}

int go_y, go_x, pe_index, shortest_route;

int BFS(int index, bool mode) { // mode false : start, true : dest;
	bool flag = false;
	int goal_y, goal_x;
	int result = 1000000;
	bool visited[MAX + 1][MAX + 1] = {};
	int dy[4] = { -1,1,0,0 }, dx[4] = { 0,0,-1,1 };

	if (!mode) {
		goal_y = pe_arr[index].start_y;
		goal_x = pe_arr[index].start_x;
	}
	else {
		goal_y = pe_arr[index].dest_y;
		goal_x = pe_arr[index].dest_x;
	}

	queue<BFS_STRUCT> q;
	q.push({ car_y, car_x, 0 });
	visited[car_y][car_x] = true;

	if (car_y == goal_y && car_x == goal_x) return 0;
	while (!q.empty()) {
		int now_y = q.front().y, now_x = q.front().x, now_route = q.front().route; q.pop();

		for (int i = 0; i < 4; i++) {
			int new_y = now_y + dy[i], new_x = now_x + dx[i];
			if (new_y > N || new_x > N || new_y <= 0 || new_x <= 0
				|| visited[new_y][new_x] || map[new_y][new_x] == 1) continue;
			if (new_y == goal_y && new_x == goal_x && result > now_route + 1) {
				result = now_route + 1;
				flag = true;
				continue;
			}

			q.push({ new_y, new_x, now_route + 1 });
			visited[new_y][new_x] = true;
		}
	}

	if (!flag) return -1;
	return result;
}

bool choose() {
	shortest_route = 1000000;
	bool flag = false;
	for (int i = 0; i < M; i++) {
		if (pe_arr[i].finish) continue;

		int bfs_result = BFS(i, false);
		if (bfs_result < 0) continue;
		flag = true;

		if (bfs_result < shortest_route) {
			pe_index = i; go_y = pe_arr[i].start_y; go_x = pe_arr[i].start_x; shortest_route = bfs_result;
		}
		else if (bfs_result == shortest_route) {
			if (pe_arr[i].start_y < go_y) {
				pe_index = i; go_y = pe_arr[i].start_y; go_x = pe_arr[i].start_x; shortest_route = bfs_result;
			} else if (pe_arr[i].start_y == go_y) {
				if (pe_arr[i].start_x < go_x) {
					pe_index = i; go_y = pe_arr[i].start_y; go_x = pe_arr[i].start_x; shortest_route = bfs_result;
				}
			}
		}
	}

	if (!flag) return false;

	move_people++;
	car_y = go_y;
	car_x = go_x;
	fuel -= shortest_route;
	pe_arr[pe_index].finish = true;

	if (fuel < 0) return false;

	return true;
}

bool go() {
	int bfs_result = BFS(pe_index, true);
	if (bfs_result < 0) return false;

	car_y = pe_arr[pe_index].dest_y;
	car_x = pe_arr[pe_index].dest_x;
	fuel -= bfs_result;
	if (fuel >= 0) fuel += (bfs_result * 2);
	else return false;

	return true;
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);

	input();

	while (move_people < M) {
		if (!choose()) {
			cout << -1;
			return 0;
		}

		if (!go()) {
			cout << -1;
			return 0;
		}
	}
	cout << fuel;
	return 0;
}

'coding > baekjoon_codingstudy' 카테고리의 다른 글

12100 2048(Easy)  (0) 2022.10.03
21609 상어중학교  (0) 2022.10.02
13460 구슬 탈출2  (0) 2022.10.02
14891 톱니바퀴 (골드 5)  (0) 2021.10.05
18239 편안한 수열 만들기 (골드 3)  (0) 2021.08.19

13460 구슬 탈출 2 > 2024KB, 28ms

BFS로 풀어볼 것

 

내가 푼 방법 : 

  • 기본적으로 DFS로 풀었음
  • 상하좌우 DFS 반복해주되 만약 그 방향으로 했을 때 공이 움직이지 않았다면 그 방향은 제외해주고 DFS (while_cnt)
  • 공만 움직이고 map은 그대로이기 때문에 map은 그대로 놔두고 빨간공과 파란공의 위치만 저장하고 복사함
    • 처음에는 map 모두 복사했다가 시간초과
  • 간단한 로직
    • 상하좌우 DFS 들어감
    • 빨간 공 움직이고 파란 공 움직임
    • 각 움직임은 함수로 구현했는데 0 : 안움직 안들어감, 1 : 움직 안들어감, 2 : 움직 들어감을 뜻함
    • 만약 둘 다 안움직였으면 한 차례가 끝난 것이고 파란색이 들어갔으면 종료, 빨간색이 들어갔으면 빨간색은 이제 안 움직인다고 생각하고 파란색을 움직임. 여기서 파란색이 들어가면 종료, 파란색이 안들어가면 움직인 최솟값이랑 비교해서 갱신 시켜줌

 

=> 다른 사람들에 비해 느리고 메모리 많이 먹음.

 

#include <iostream>
#include <string>

#define MAX 10
using namespace std;

typedef struct r {
    int y, x;
}R;

typedef struct b {
    int y, x;
}B;

int result = 100;
int N, M;
string map[MAX];
R ori_r;
B ori_b;

int dy[4] = { -1, 1, 0, 0 }, dx[4] = { 0,0,-1,1 };

void input() {
    cin >> N >> M;

    for (int i = 0; i < N; i++)
        cin >> map[i];
   
    for (int i = 0; i < N; i++)
        for (int j = 0; j < M; j++) {
            if (map[i][j] == 'R') {
                ori_r.y = i; ori_r.x = j;
                map[i][j] = '.';
            }
            if (map[i][j] == 'B') {
                ori_b.y = i; ori_b.x = j;
                map[i][j] = '.';
            }
        }
}

int red_move(int dir, R& r_ori, B& b_ori) {
    int new_y, new_x;
    int b_y = b_ori.y, b_x = b_ori.x, r_y = r_ori.y, r_x = r_ori.x;
    new_y = r_y + dy[dir]; new_x = r_x + dx[dir];
    while (map[new_y][new_x] == '.' && !(new_y == b_y && new_x == b_x)) { 
        new_y += dy[dir]; new_x += dx[dir]; 
    }

    switch (map[new_y][new_x]) {
    case 'O':
        r_ori.y = -1, r_ori.x = -1;
        return 2;
    case '#':
        if (new_y - dy[dir] == r_y && new_x - dx[dir] == r_x)
            return 0;
        else {
            r_ori = { new_y - dy[dir], new_x - dx[dir] };
            return 1;
        }
    case '.':
        if (new_y - dy[dir] == r_y && new_x - dx[dir] == r_x)
            return 0;
        else {
            r_ori = { new_y - dy[dir], new_x - dx[dir] };
            return 1;
        }
    }
}

int blue_move(int dir, R &r_ori, B &b_ori) {
    int new_y, new_x;
    int b_y = b_ori.y, b_x = b_ori.x, r_y = r_ori.y, r_x = r_ori.x;
    new_y = b_y + dy[dir]; new_x = b_x + dx[dir];
    while (map[new_y][new_x] == '.' && !(new_y == r_y && new_x == r_x)) {
        new_y += dy[dir]; new_x += dx[dir];
    }

    switch (map[new_y][new_x]) {
    case 'O':
        b_ori.y = -1, b_ori.x = -1;
        return 2;
    case '#':
        if (new_y - dy[dir] == b_y && new_x - dx[dir] == b_x)
            return 0;
        else {
            b_ori = { new_y - dy[dir], new_x - dx[dir] };
            return 1;
        }
    case '.':
        if (new_y - dy[dir] == b_y && new_x - dx[dir] == b_x)
            return 0;
        else {
            b_ori = { new_y - dy[dir], new_x - dx[dir] };
            return 1;
        }
    }
}

void DFS(int dir, int cnt, R r_ori, B b_ori) {
    if (cnt == 11) return;

    R r_copy = { r_ori.y, r_ori.x };
    B b_copy = { b_ori.y, b_ori.x };

    int red_result = red_move(dir, r_copy, b_copy);
    int blue_result = blue_move(dir, r_copy, b_copy);
    bool red_flag = false;
    int while_cnt = 0;
    // 0 : 안움직 안들어감, 1 : 움직 안들어감, 2 : 움직 들어감
    while (1) {
        if (red_result == 0 && blue_result == 0) break;

        if (blue_result == 2) return;
        if (red_result == 2) red_flag = true;

        if (red_flag) red_result = 0;
        else red_result = red_move(dir, r_copy, b_copy);

        blue_result = blue_move(dir, r_copy, b_copy);
        
        while_cnt++;
    }

    if (red_flag) {
        if (result > cnt) {
            result = cnt;
        }
        return;
    }
        

    for (int i = 0; i < 4; i++) {
        if (while_cnt == 0 && i == dir) continue;
        DFS(i, cnt + 1, r_copy, b_copy);
    }
        
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);

    input();

    for (int i = 0; i < 4; i++)
        DFS(i, 1, ori_r, ori_b);
    
    if (result == 100) cout << -1;
    else cout << result;
}

'coding > baekjoon_codingstudy' 카테고리의 다른 글

21609 상어중학교  (0) 2022.10.02
19238 스타트택시  (0) 2022.10.02
14891 톱니바퀴 (골드 5)  (0) 2021.10.05
18239 편안한 수열 만들기 (골드 3)  (0) 2021.08.19
11657 타임머신 (골드 4)  (0) 2021.08.15

알고리즘 분류 : 구현, 시뮬레이션

 

이번 문제는 단순히 주어진 조건에 따라 구현을 해내면 되는 문제였다.

 

 

 

문제를 먼저 해석하자면 톱니바퀴가 아래와 같은 모양으로 4개가 주어진다. 순서대로 1,2,3,4 바퀴이다.

 

톱니바퀴 중 하나는 시계방향, 반시계 방향으로 돌릴 수 있다.

반시계 / 시계

이때, 양 옆의 톱니바퀴는 돌아가는 톱니바퀴와 같은 극성이라면 돌리지 않고,

다른 극성이라면 돌아가는 톱니바퀴와 반대 방향으로 돌아간다.

 

처음에 돌릴 바퀴가 주어지면 양옆의 바퀴가 돌아가거나 돌아가지 않고, 돌아간다면 양 옆의 바퀴가 또 돌아가거나 돌아가지 않고 ...  이런 식으로 연쇄적인 반응이 나타난다.

 

 

 

문제를 푼 방식은 우선 돌리기 직전 상황의 바퀴 정보를 저장해두는 것이다.

12시 방향의 톱니를 1이라고 하고 시계방향으로 번호를 매겨준다면

1번 바퀴의 3번과 2번 바퀴의 7번, 2번 바퀴의 3번과 3번 바퀴의 7번, 3번 바퀴의 3번과 4번 바퀴의 7번이 맞물린다.

따라서 돌리기 직전 bool three_wh[5], seven_wh(5]의 배열을 이용해서 각 톱니바퀴의 3번과 7번을 저장해두었다.

 

 

또한 연쇄반응을 이용했는데

1번에서 시작 -> 2번 -> 3번 -> 4번

2번에서 시작 -> 1번

                  -> 3번 -> 4번

3번에서 시작 -> 2번 -> 1번

                  -> 4번

4번에서 시작 -> 3번 -> 2번 -> 1번 

이런 식으로 움직이기 때문에 내 옆에서 돌기 시작한 바퀴의 번호와 그 방향을 알려주면 맞물린 곳을 비교한 후, 같으면 돌지 않고 다르면 반대 방향으로 돌았다.

만약 내가 처음으로 돌기 시작했다면 내 옆에서 돌기 시작한 바퀴는 0번으로 예외처리를 해두었다.

이 부분은 코드 주석을 보는 게 이해가 훨씬 빠르다!

//톱니바퀴 골드 5
#include<iostream>

using namespace std;

string wheel[5];
bool three_wh[5], seven_wh[5];

void one(int start, int turn);
void two(int start, int turn);
void three(int start, int turn);
void four(int start, int turn);

// 같으면 안움직이고 다르면 반대 방향으로
void wise(int turn, int w) {
	if (turn == 1) {
		int temp = wheel[w][7];
		for (int j = 7;j > 0;j--) {
			wheel[w][j] = wheel[w][j - 1];
		}
		wheel[w][0] = temp;
	}
	else {
		int temp = wheel[w][0];
		for (int j = 0;j < 7;j++) {
			wheel[w][j] = wheel[w][j + 1];
		}
		wheel[w][7] = temp;
	}
	
}

void one(int start, int turn) {
	//단독 시작
	if (!start) {
		two(1,turn); 

		wise(turn, 1);
	}
	else { //2번 시작
		if (three_wh[1] == seven_wh[2]) return;
		else wise(-turn, 1);
	}
	
}

void two(int start, int turn) {
	// 단독 시작
	if (!start) {
		one(2,turn);
		three(2,turn);

		wise(turn, 2);
	}
	
	if (start == 1) { // 1번 시작 -> 3번으로
		if (three_wh[1] == seven_wh[2]) return;

		three(2, -turn);

		wise(-turn, 2);
	}
	else if (start == 3) { // 3번 시작 -> 1번으로
		if (three_wh[2] == seven_wh[3]) return;

		one(2, -turn);

		wise(-turn, 2);
	}
}

void three(int start, int turn) {
	// 단독 시작
	if (!start) {
		two(3, turn);
		four(3, turn);

		wise(turn, 3);
	}

	if (start == 2) { // 2번 시작 -> 4번으로
		if (three_wh[2] == seven_wh[3]) return;

		four(3, -turn);

		wise(-turn, 3);
	}
	else if (start == 4) { // 4번 시작 -> 2번으로
		if (three_wh[3] == seven_wh[4]) return;

		two(3, -turn);

		wise(-turn, 3);
	}
}

void four(int start, int turn) {
	//단독 시작
	if (!start) {
		three(4, turn);

		wise(turn, 4);
	}
	else { //3번 시작
		if (three_wh[3] == seven_wh[4]) return;
		else wise(-turn, 4);
	}

}

int main() {
	
	for (int i = 1; i < 5;i++) {
		cin >> wheel[i]; // N극은 0, S극은 1
	}

	int K; cin >> K;
	int w, t, temp;
	

	for (int i = 0;i < K;i++) {
		for (int j = 1;j < 5;j++) {
			three_wh[j] = wheel[j][2] - 48;
			seven_wh[j] = wheel[j][6] - 48;
		}

		cin >> w >> t;
		switch (w) {
		case 1:
			one(0, t);
			break;
		case 2:
			two(0, t);
			break;
		case 3:
			three(0, t);
			break;
		case 4:
			four(0, t);
			break;
		}
	}

	cout << (wheel[1][0] - 48) * 1 + (wheel[2][0] - 48) * 2 + (wheel[3][0] - 48) * 4 + (wheel[4][0] - 48) * 8;

}

//2024KB, 0ms

 

 

'coding > baekjoon_codingstudy' 카테고리의 다른 글

19238 스타트택시  (0) 2022.10.02
13460 구슬 탈출2  (0) 2022.10.02
18239 편안한 수열 만들기 (골드 3)  (0) 2021.08.19
11657 타임머신 (골드 4)  (0) 2021.08.15
4386 별자리 만들기 (골드 4)  (0) 2021.08.15

이번 문제는 애드 훅이 주제인 문제이다.

 

애드 훅이란 뚜렷한 알고리즘이 없는 문제를 말한다.

결국 그냥 어떤 알고리즘을 응용하는 게 아닌 이 문제만의 풀이가 있다는 뜻이다.

 

 

 

우선 문제 설명을 하자면 입력으로는 N과 K가 주어진다.

1~N까지의 배열이 존재하는데 뒤쪽 K개의 수를 앞으로 이동시켰을 때,

swap과 reverse를 이용해 정확히 5번만에 원래대로 수열을 되돌려 놓을 수 있는지, 그리고 그 방법을 출력하는 문제이다.

N = 7, K = 3

 

 

4가지의 예외 상황을 제외하고는 모두 같은 풀이로 풀 수 있다.

 

같은 풀이도 여러가지가 있는데 내가 찾은 건 두 가지 방법이다.

더보기

1. 바뀐 수열에서 reverse 1 K, reverse K+1 N, reverse 1 N(여기까지 하면 오름차순 정렬), reverse 1 N, reverse 1 N

2. 바뀐 수열에서 reverse 1 N, reverse 1 N-K, reverse N-K+1 N(여기까지 하면 오름차순 정렬), reverse 1 N, reverse 1 N

 

4가지의 예외 상황은 

1. N == 2

2. N == 3

3. 1,2 상황을 제외하고 K == 1

4. 1,2 상황을 제외하고 K == N - 1

 

 

1의 경우는 그냥 swap 1 2를 5번 해주면 된다.

3의 경우는 swap 1 2, swap 2 N, reverse 2 N-1, reverse 1 N, reverse 1 N

 

4의 경우는 3의 경우와 반대로 해주면 된다.'

 

 

2의 경우는 1 2 3 이 되는 경우가 없으므로 NO인데 이는 밑의 표로 입증가능하다. 

(이건 스터디 하면서 배움..)

 

// 편안한 수열 만들기 (골드 3)
#include <iostream>

using namespace std;

int N, K;

int main() {

	cin.tie(NULL);
	cout.tie(NULL);
	ios::sync_with_stdio(false);

	cin >> N >> K;

	// 2~3
	if (N == 2) { // K = 1
		cout << "YES" << '\n'; // ( 2 1 )  1 2    2 1   1 2    2 1   1 2
		cout << "reverse " << 1 << " " << 2 << '\n';
		cout << "reverse " << 1 << " " << 2 << '\n';
		cout << "reverse " << 1 << " " << 2 << '\n';
		cout << "reverse " << 1 << " " << 2 << '\n';
		cout << "reverse " << 1 << " " << 2 << '\n';

		return 0;
	}
	else if (N == 3) {
		cout << "NO";
        
		return 0;

	}


	// 4~
	if (K == 1) {
		cout << "YES" << '\n';
		cout << "swap " << 1 << " " << 2 << '\n';
		cout << "reverse " << 2 << " " << N << '\n';
		cout << "reverse " << 2 << " " << N - 1 << '\n';
		cout << "reverse " << 1 << " " << N << '\n';
		cout << "reverse " << 1 << " " << N << '\n';
	}
	else if (K == N - 1) {
		cout << "YES" << '\n';
		cout << "swap " << N - 1 << " " << N << '\n';
		cout << "reverse " << 1 << " " << N - 1 << '\n';
		cout << "reverse " << 2 << " " << N - 1 << '\n';
		cout << "reverse " << 1 << " " << N << '\n';
		cout << "reverse " << 1 << " " << N << '\n';
	}
	else
	{
		cout << "YES" << '\n';
		cout << "reverse " << 1 << " " << K << '\n';
		cout << "reverse " << K + 1 << " " << N << '\n';
		cout << "reverse " << 1 << " " << N << '\n';
		cout << "reverse " << 1 << " " << N << '\n';
		cout << "reverse " << 1 << " " << N << '\n';
	}

	return 0;
}
// 2020KB, 0ms

 

 

#include <iostream>

using namespace std;

int N, K;

int main() {
	cin >> N >> K;


	if (N == 3) {
		cout << "NO";
		return 0;
	}

	if (N == 2) {
		cout << "YES" << '\n';
		cout << "swap " << 1 << ' ' << 2 << '\n';
		cout << "swap " << 1 << ' ' << 2 << '\n';
		cout << "swap " << 1 << ' ' << 2 << '\n';
		cout << "swap " << 1 << ' ' << 2 << '\n';
		cout << "swap " << 1 << ' ' << 2 << '\n';

		return 0;
	}

	if (K == 1) {
		cout << "YES" << '\n';
		cout << "swap " << 1 << ' ' << 2 << '\n';
		cout << "reverse " << 2 << ' ' << N << '\n';
		cout << "reverse " << 2 << ' ' << N - 1 << '\n';
		cout << "reverse " << 1 << ' ' << N << '\n';
		cout << "reverse " << 1 << ' ' << N << '\n';

	}
	else if (K == N - 1) {   
		cout << "YES" << '\n';
		cout << "swap " << N - 1 << ' ' << N << '\n'; 
		cout << "reverse " << 1 << ' ' << N - 1 << '\n'; 
		cout << "reverse " << 2 << ' ' << N - 1 << '\n'; 
		cout << "reverse " << 1 << ' ' << N << '\n'; 
		cout << "reverse " << 1 << ' ' << N << '\n';

	}
	else {
		cout << "YES" << '\n';
		cout << "reverse " << 1 << ' ' << N << '\n';
		cout << "reverse " << 1 << ' ' << N - K << '\n';
		cout << "reverse " << N - K + 1 << ' ' << N << '\n';
		cout << "reverse " << 1 << ' ' << N << '\n';
		cout << "reverse " << 1 << ' ' << N << '\n';
	}

	return 0;
}

// 2020 KB, 0ms

'coding > baekjoon_codingstudy' 카테고리의 다른 글

13460 구슬 탈출2  (0) 2022.10.02
14891 톱니바퀴 (골드 5)  (0) 2021.10.05
11657 타임머신 (골드 4)  (0) 2021.08.15
4386 별자리 만들기 (골드 4)  (0) 2021.08.15
17404 RGB 거리2 (골드 4)  (0) 2021.08.15

벨만-포드 알고리즘을 그냥 구현하면 되는 문제이다.

나는 https://yabmoons.tistory.com/365 이 사이트를 참고했다.

벨만-포드 알고리즘을 설명해주는 사이트지만 거의 정답..!! 엄청 잘 설명되어있다.

벨만-포드 알고리즘의 핵심은 계산된 노드만 본다 & N-1번 반복 두 개!

 

 

문제 설명을 하자면 From, To, Cost가 주어지고 1번 node에서 다른 node까지의 최소 거리를 구하는 문제이다.

근데 음의 사이클이 하나라도 존재한다면 -1을 출력해야 한다.

 

 

 

한 가지 문제가 발생했던 부분은 자꾸 출력 초과가 발생했던 문제였다.

문제 검색에 찾아보니 underflow 때문에 발생하는 문제였다.

dist의 자료형을 int->long으로 변경했더니 문제가 해결됐다.

 

 

// 타임머신 (골드 4)

//dist를 long으로 안하면 출력 초과가 남 ( underflow 때문에 )

#include <iostream>
#include <limits>

using namespace std;

int N, M;
pair<pair<int, int>, int>* graph;
long* dist;

void Bellman_Ford() {
	int From, To, cost;

	dist[1] = 0;
	
	for (int i = 0;i < N + 1;i++) { //N+1번 반복
		for (int j = 0;j < M;j++) {
			
			From = graph[j].first.first;
			To = graph[j].first.second;
			cost = graph[j].second;

			if (dist[From] == numeric_limits<int>::max()) continue; // 한 번도 방문x 넘김

			if (dist[To] > dist[From] + cost) {
				dist[To] = dist[From] + cost;
			}
		}
	}

	for (int i = 0; i < M;i++) {
		From = graph[i].first.first;
		To = graph[i].first.second;
		cost = graph[i].second;

		if (dist[From] == numeric_limits<int>::max()) continue;
		if (dist[To] > dist[From] + cost) {
			cout << "-1"; return;
		}
	}

	for (int i = 2;i < N + 1;i++) {
		if (dist[i] == numeric_limits<int>::max()) cout << "-1" << '\n';
		else cout << dist[i] << '\n';
	}


}


int main() {

	cin.tie(NULL);
	cout.tie(NULL);
	ios::sync_with_stdio(false);

	cin >> N >> M;

	graph = new pair<pair<int, int>, int>[M];

	dist = new long[N + 1]{};

	for (int i = 0;i < M;i++) {  // From To cost 입력
		cin >> graph[i].first.first >> graph[i].first.second >> graph[i].second;
	}

	for (int i = 1;i < N + 1;i++) {
		dist[i] = numeric_limits<int>::max(); // 거리 inf
	}

	Bellman_Ford();

	delete[] graph, dist;

	return 0;
}

// 2212KB, 8ms

'coding > baekjoon_codingstudy' 카테고리의 다른 글

14891 톱니바퀴 (골드 5)  (0) 2021.10.05
18239 편안한 수열 만들기 (골드 3)  (0) 2021.08.19
4386 별자리 만들기 (골드 4)  (0) 2021.08.15
17404 RGB 거리2 (골드 4)  (0) 2021.08.15
1149 RGB 거리 (실버1)  (0) 2021.08.12

이 문제는 모든 노드가 연결되어 있는 그래프에서 최소 스패닝 트리를 만드는 문제이다.

단, 간선의 가중치가 나와있지 않아서 이것만 미리 구해주면 된다.

 

 

 

이 문제를 풀면서 최소 스패닝 트리에 대해서 공부해보았는데, 

우선 스패닝 트리란 그래프 내의 모든 정점을 포함하는 트리이다.

따라서 최소 스패닝 트리는 그래프 내의 모든 정점을 포함하면서 간선들의 가중치 합이 최소여야 한다.

 

 

최소 스패닝 트리를 만드는 방법은 두 가지 방법이 있는데 나는 그 중 크루스칼 알고리즘을 사용했다.

크루스칼 알고리즘은 가중치를 오름차순으로 정렬한다음 맨 앞의 간선부터 연결해주면 된다.

근데 최소 스패닝 트리이므로 사이클이 생기면 안된다. 그래서 노드들의 부모를 확인해주고 부모가 서로 같다면 연결x, 다르다면 연결하는 방식으로 진행된다.

 

즉, 

1. 가중치가 가장 작은 간선 선택 후 노드 확인

2. 노드들의 부모를 찾음. -> find함수

3. 부모가 같다면 연결하지 않고 넘어감. 부모가 다르다면 최초 부모를 서로 연결해줌 -> Union 함수

이 3가지 단계를 반복해주면 된다.

 

 

// 별자리 만들기 (골드4)
#include<iostream>
#include<vector>
#include<algorithm>
#include<math.h>

using namespace std;

pair<double, double>* arr;
vector<pair<double, pair<double, double>>> V;
int N;
int* parent;

void cal() {
	double cost;
	double x1, x2, y1, y2;

	for (int i = 0;i < N;i++) {
		for (int j = i + 1;j < N;j++) {
			x1 = arr[i].first; y1 = arr[i].second;
			x2 = arr[j].first; y2 = arr[j].second;

			cost = sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));


			V.push_back(make_pair(cost, make_pair(i,j)));
		}
	}

	sort(V.begin(), V.end());

	/*for (int i = 0;i < 3;i++) {
		cout << V[i].second.first << " " << V[i].second.second << " " << V[i].first << endl;
	}*/

	delete[] arr;

}

int find(int x) {
	if (parent[x] == x) return x;
	return parent[x] = find(parent[x]);
}

void Union(int x, int y) {
	x = find(x);
	y = find(y);

	parent[y] = x;
}


int main() {
	double Ans = 0;

	cin >> N;

	arr = new pair<double, double>[N];
	parent = new int[N];

	for (int i = 0;i < N;i++) {
		cin >> arr[i].first >> arr[i].second;
		parent[i] = i;
	}

	cal();
	
	//cout << endl << endl;

	for (int i = 0;i < V.size();i++) {
		//cout << V[i].second.first << " " << V[i].second.second << endl;
		if (find(V[i].second.first) != find(V[i].second.second)) {
			Union(V[i].second.first,V[i].second.second);
			Ans += V[i].first;
		}
	}

	cout.precision(3);
	cout << Ans;

	return 0;
}

// 2432KB, 0ms

'coding > baekjoon_codingstudy' 카테고리의 다른 글

14891 톱니바퀴 (골드 5)  (0) 2021.10.05
18239 편안한 수열 만들기 (골드 3)  (0) 2021.08.19
11657 타임머신 (골드 4)  (0) 2021.08.15
17404 RGB 거리2 (골드 4)  (0) 2021.08.15
1149 RGB 거리 (실버1)  (0) 2021.08.12

1149 RGB 거리 문제에 조건 하나만 더 추가된 문제이다.

 

1149 문제는 1번은 2번과, N번은 N-1번과 다른 색이어야 하고, 1과 N을 제외한 나머지 i번째는 i-1번째 집과 i+1째 집과 다른 색이어야 하는 문제였다.

17404 문제는 1번과 N번이 다른 색이어야 하는 조건이 추가되었다.

 

 

 

이건 1149 문제와 같은 점화식을 사용한다.

더보기

d[i][0] = Min(d[i - 1][1], d[i - 1][2]) + a[0];
d[i][1] = Min(d[i - 1][0], d[i - 1][2]) + a[1];

d[i][2] = Min(d[i - 1][0], d[i - 1][1]) + a[2];

단, 1번째 집이 R을 선택했을 경우 N번째 집은 R을 선택하지 못한다는 것만 주의해주면 된다.

 

 

 

해결 방식은 1번이 무조건 R/G/B를 고르게 한 뒤에 N번은 1번이 고른 색과 다른 색을 골라서 그 두 가지 경우를 비교한 후 값이 작은 수를 저장해놓고 이를 3번 반복하는 것이다.

 

무조건 1번이 R/G/B를 고르게 하는 방법은 고를 색 빼고는 엄청 큰 값을 넣어주면 된다.

 

 

// RGB 거리 2 (골드 4)

#include <iostream>

using namespace std;

//점화식: d[i][0] = Min(d[i - 1][1], d[i - 1][2]) + a[0];
//		  d[i][1] = Min(d[i - 1][0], d[i - 1][2]) + a[1];
//		  d[i][2] = Min(d[i - 1][0], d[i - 1][1]) + a[2];

int** d;
int** RGB;
int N;

void dynamic(int x) {

	if (x == 0) return;

	dynamic(x - 1);

	d[x][0] = min(d[x - 1][1], d[x - 1][2]) + RGB[x][0];
	d[x][1] = min(d[x - 1][0], d[x - 1][2]) + RGB[x][1];
	d[x][2] = min(d[x - 1][0], d[x - 1][1]) + RGB[x][2];

		//cout << d[x][0] << " " << d[x][1] << " " << d[x][2] << endl;

}

int main() {
// 입력
	cin >> N;

	RGB = new int* [N + 1]{};
	d = new int* [N + 1]{};
	d[0] = new int[3]{};
	RGB[0] = new int[3]{};
	for (int i = 1;i < N + 1;i++) {
		d[i] = new int[3]{};
		RGB[i] = new int[3]{};
		cin >> RGB[i][0] >> RGB[i][1] >> RGB[i][2];
	}

// 풀이
	int Ans;
	int G_1 = RGB[1][1], B_1 = RGB[1][2];

	RGB[1][1] = 10000; RGB[1][2] = 10000;

	//1번집 R
	dynamic(N);
	Ans = min(d[N][1], d[N][2]);

		//cout << endl << endl;


	//1번집 G
	RGB[1][0] = 10000; RGB[1][1] = G_1; RGB[1][2] = 10000;
	dynamic(N);
	if (Ans > min(d[N][0], d[N][2])) Ans = min(d[N][0], d[N][2]);

		//cout << endl << endl;


	//1번집 B
	RGB[1][0] = 10000; RGB[1][1] = 10000; RGB[1][2] = B_1;
	dynamic(N);
	if (Ans > min(d[N][0], d[N][1])) Ans = min(d[N][0], d[N][1]);
	
		//cout << endl << endl;

	cout << Ans;

	return 0;
}

// 2020KB, 0ms

'coding > baekjoon_codingstudy' 카테고리의 다른 글

14891 톱니바퀴 (골드 5)  (0) 2021.10.05
18239 편안한 수열 만들기 (골드 3)  (0) 2021.08.19
11657 타임머신 (골드 4)  (0) 2021.08.15
4386 별자리 만들기 (골드 4)  (0) 2021.08.15
1149 RGB 거리 (실버1)  (0) 2021.08.12

+ Recent posts