[문제 링크]

 

1005번: ACM Craft

첫째 줄에는 테스트케이스의 개수 T가 주어진다. 각 테스트 케이스는 다음과 같이 주어진다. 첫째 줄에 건물의 개수 N 과 건물간의 건설순서규칙의 총 개수 K이 주어진다. (건물의 번호는 1번부�

www.acmicpc.net


 먼저 입력으로 주어지는 건설 순서대로 그래프를 만든다. 필자는 역순으로 탐색할 계획이었기 때문에 X, Y 를 입력받았으면 Y정점에서 X정점으로 가는 간선을 연결하였다.

 

 그래프를 연결했으면 승리를 위한 건물을 시작정점으로 하는 깊이 우선 탐색을 수행하는데, 현재 정점의 건물까지 짓는데 걸리는 시간은 (현재 정점에서 건물을 짓는 시간 + 현재 정점에서 갈 수 있는 정점의 건물을 짓는데 걸리는 시간들 중 가장 큰 값) 이므로 이를 그대로 구현해주면 된다.

 

 추가로 이미 계산한 정점을 다시 호출하는 경우가 많으면 시간복잡도가 커지게 되므로 동적 계획법의 메모이제이션 기법을 통해 한번 계산한 정점의 최소 시간을 저장하여 중복되는 연산을 최소화해야 한다.


#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;

int N, K;
vector<int> adj[1001];
vector<int> weight(1001);
int memo[1001];

int dfs(int start) {
	int& ret = memo[start];
	if (ret != -1) return ret;

	ret = 0;

	for (int i = 0; i < adj[start].size(); i++) {
		int next = adj[start][i];
		ret = max(ret, dfs(next));
	}
	ret += weight[start];

	return ret;
}

int main(void) {
	int tc;
	cin >> tc;

	while (tc--) {
		memset(memo, -1, sizeof(memo));

		for (int i = 0; i < 1001; i++)
			adj[i].clear();

		cin >> N >> K;

		for (int i = 1; i <= N; i++)
			cin >> weight[i];

		for (int i = 0; i < K; i++) {
			int a, b;
			cin >> a >> b;
			adj[b].push_back(a);
		}

		int W;
		cin >> W;
		
		cout << dfs(W) << endl;
	}

	return 0;
}

알고리즘 200일 프로젝트 - 166 day

'알고리즘 > BOJ' 카테고리의 다른 글

백준 2146번: 다리 만들기  (0) 2020.09.22
백준 5014번: 스타트링크  (0) 2020.09.22
백준 7562번: 나이트의 이동  (0) 2020.09.21
백준 2589번: 보물섬  (0) 2020.09.21
백준 16234번: 인구 이동  (0) 2020.09.21

[문제 링크]

 

10451번: 순열 사이클

1부터 N까지 정수 N개로 이루어진 순열을 나타내는 방법은 여러 가지가 있다. 예를 들어, 8개의 수로 이루어진 순열 (3, 2, 7, 8, 1, 4, 5, 6)을 배열을 이용해 표현하면 \(\begin{pmatrix} 1 & 2 &3&4&5&6&7&8 \\  3

www.acmicpc.net


입력으로 주어지는 순열과 1, 2, 3, ... N 순열은 서로 1:1 대응이라는 것을 알 수 있다.

따라서 입력받는 순서대로 1부터 N까지 정점을 연결한 다음, 모든 정점을 방문할 때 까지 dfs를 수행한 횟수를 출력하면 원하는 결과를 얻을 수 있다.


#include <iostream>
#include <vector>
using namespace std;

vector<int> adj(1001); // 1:1 그래프
vector<bool> visited(1001);

void dfs(int here) {
	visited[here] = true;
	int there = adj[here];
	if (!visited[there]) dfs(there);
}

int main(void) {
	int tc;
	cin >> tc;

	while (tc--) {
		int N;
		cin >> N;
		visited = vector<bool>(N + 1, false);

		for (int i = 1; i <= N; i++) {
			int num;
			cin >> num;
			adj[i] = num;
		}

		int cnt = 0;
		for (int i = 1; i <= N; i++) {
			if (!visited[i]) {
				cnt++;
				dfs(i);
			}
		}

		cout << cnt << endl;
	}

	return 0;
}

알고리즘 200일 프로젝트 - 165 day

'알고리즘 > BOJ' 카테고리의 다른 글

백준 16234번: 인구 이동  (0) 2020.09.21
백준 1261번: 알고스팟  (0) 2020.09.21
백준 2573번: 빙산  (0) 2020.09.21
백준 11404번: 플로이드  (0) 2020.09.20
백준 1701번: Cubeditor  (0) 2020.09.20

[문제 링크]

 

2573번: 빙산

첫 줄에는 이차원 배열의 행의 개수와 열의 개수를 나타내는 두 정수 N과 M이 한 개의 빈칸을 사이에 두고 주어진다. N과 M은 3 이상 300 이하이다. 그 다음 N개의 줄에는 각 줄마다 배열의 각 행을 �

www.acmicpc.net


 문제를 해결하기 위해 4가지 과정을 반복하였다.

 

1) iceMelt() 함수를 통해 빙산 주변에 있는 물의 수만큼 빙산을 녹인다.

 

2) 빙산이 2개 이상으로 나뉘어져 있는지 확인하기 위해 isSeparate() 함수를 정의하고, dfs() 를 통해 한 덩어리에 속한 빙산을 방문한다.

 

3)  만약 dfs()를 수행할 빙산이 없다면 모두 녹았다는 의미로 2를 반환한다.

 

4) dfs()를 수행했는데 아직 방문하지 않은 빙산이 있다면 분리되었다는 의미인 1을 반환하고, 모두 방문했다면 2개 이상으로 분리되지 않았다는 의미인 0을 반환한다.

 

isSeparate() 이 0을 반환했다면 위 과정을 다시 수행하고, 1을 반환했다면 누적한 시간을 출력, 2를 반환했다면 0을 출력한다.


#include <iostream>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;

struct Pos {
	int y;
	int x;
};

int N, M;
int board[300][300];
bool visited[300][300];
int dy[4] = { 0, 0, 1, -1 };
int dx[4] = { 1, -1, 0, 0 };

void dfs(Pos here) {
	visited[here.y][here.x] = true;

	for (int i = 0; i < 4; i++) {
		int ny = here.y + dy[i];
		int nx = here.x + dx[i];
		if (ny >= 0 && ny < N && nx >= 0 && nx < M)
			if (!visited[ny][nx] && board[ny][nx] != 0)
				dfs({ ny, nx });
	}
}

int isSeparate() {
	memset(visited, false, sizeof(visited));

	bool check = false;
	for (int i = 0; i < N; i++)
		for (int j = 0; j < M; j++)
			if (board[i][j] != 0 && !visited[i][j]) {
				if (!check) {
					dfs({ i, j });
					check = true;
				}
				else 
					return 1;
			}

	if (!check) 
		return 2;
	else 
		return 0;
}

void iceMelt() {
	int temp[300][300];
	memcpy(temp, board, sizeof(board));

	for(int i=0; i<N; i++)
		for (int j = 0; j < M; j++) {
			if (temp[i][j] != 0) {
				int water = 0;
				for (int k = 0; k < 4; k++) {
					int ny = i + dy[k];
					int nx = j + dx[k];
					if (ny >= 0 && ny < N && nx >= 0 && nx < M)
						if (temp[ny][nx] == 0) water++;
				}
				board[i][j] -= water;
				if (board[i][j] < 0) board[i][j] = 0;
			}
		}
}

int solution() {
	int years = 0;
	int separate = isSeparate();

	while (separate == 0) {
		years++;
		iceMelt();
		separate = isSeparate();
	}

	if (separate == 1)
		return years;
	else
		return 0;
}

int main(void) {
	cin >> N >> M;

	for (int i = 0; i < N; i++)
		for (int j = 0; j < M; j++)
			cin >> board[i][j];

	cout << solution() << endl;

	return 0;
}

알고리즘 200일 프로젝트 - 165 day

'알고리즘 > BOJ' 카테고리의 다른 글

백준 1261번: 알고스팟  (0) 2020.09.21
백준 10451번: 순열 사이클  (0) 2020.09.21
백준 11404번: 플로이드  (0) 2020.09.20
백준 1701번: Cubeditor  (0) 2020.09.20
백준 16236번: 아기 상어  (0) 2020.09.20

[문제 링크]

 

2667번: 단지번호붙이기

<그림 1>과 같이 정사각형 모양의 지도가 있다. 1은 집이 있는 곳을, 0은 집이 없는 곳을 나타낸다. 철수는 이 지도를 가지고 연결된 집들의 모임인 단지를 정의하고, 단지에 번호를 붙이려 한다. �

www.acmicpc.net


현재 좌표에서 동서남북 방향을 깊이 우선 탐색 함으로써 한 단지에 속하는 좌표를 방문하고 집의 개수를 저장하였다.

그리고 한번 깊이 우선 탐색을 했는데 방문하지 않은 좌표가 존재한다면 또다른 단지가 존재하는 것이므로 그 좌표를 시작으로 다시 깊이 우선 탐색 하는 것을 반복하도록 구현하였다.


#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
using namespace std;

int N;
vector<string> board(25);
bool visited[25][25];

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

struct Pos 
{
	int y;
	int x;
};

int dfs(Pos here)
{
	int ret = 1;

	for (int i = 0; i < 4; i++)
	{
		int ny = here.y + dy[i];
		int nx = here.x + dx[i];

		if (ny >= 0 && ny < N && nx >= 0 && nx < N)
			if (!visited[ny][nx] && board[ny][nx] == '1')
			{
				visited[ny][nx] = true;
				ret += dfs({ ny, nx });
			}
	}

	return ret;
}

int main(void) 
{
	cin >> N;

	for (int i = 0; i < N; i++)
		cin >> board[i];

	vector<int> result;
	for(int i=0; i<N; i++)
		for(int j=0; j<N; j++)
			if (!visited[i][j] && board[i][j] == '1')
			{
				visited[i][j] = true;
				Pos start = { i,j };
				result.push_back(dfs(start));
			}

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

	cout << result.size() << endl;
	
	for (int i = 0; i < result.size(); i++)
		cout << result[i] << endl;

	return 0;
}

알고리즘 200일 프로젝트 - 163 day

'알고리즘 > BOJ' 카테고리의 다른 글

백준 13460번: 구슬 탈출 2  (0) 2020.09.19
백준 1753번: 최단경로  (0) 2020.09.19
백준 2178번: 미로 탐색  (0) 2020.09.19
백준 1786번: 찾기  (0) 2020.08.24
백준 1062번: 가르침 (비트마스크)  (0) 2020.08.20

+ Recent posts