본문 바로가기

PS(알고리즘 문제풀이) 관련 글/PS일지

2024-02-24

-효율적인 해킹(1325, Baekjoon)

한번의 해킹으로 최대한 많은 컴퓨터를 해킹해야 함으로, 한 컴퓨터에서 BFS탐색을 하여, 몇개의 컴퓨터를 해킹 할 수 있는 지를 알아보는 단방향 그래프탐색 문제였다. 처음에 N범위가 10^4라서, 완전 탐색을 하면, O(n^2)이 걸려 시간초과가 아닐까 싶었지만 문제의 시간제한이 5초로 넉넉하기 때문에 괜찮았다.

<소스코드>

더보기
#include <stdio.h>
#include <queue>
#include <vector>

using namespace std;

int n, m;
vector <int> vec[10010];
int ch[10010], cnt[10010];

void BFS(int x)
{
	int i, j;
	queue <int> q;
	q.push(x);
	ch[x] = 1;
	while (!q.empty()) {
		int now = q.front();
		q.pop();
		for (i = 0; i < vec[now].size(); i++) {
			int now_1 = vec[now][i];
			if (ch[now_1] == 0) {
				ch[now_1] = 1;
				q.push(now_1);
			}
		}
	}
}

int main()
{
	int i, j;
	scanf("%d %d", &n, &m);
	for (i = 0; i < m; i++) {
		int x, y;
		scanf("%d %d", &x, &y);
		vec[y].push_back(x);
	}
	int ans = -2e9;
	for (i = 1; i <= n; i++) {
		for (j = 1; j <= n; j++) ch[j] = 0;
		BFS(i);
		for (j = 1; j <= n; j++) if (ch[j] == 1) cnt[i]++;
		if (cnt[i] > ans) ans = cnt[i];
	}
	for (i = 1; i <= n; i++) {
		if (ans == cnt[i]) printf("%d ", i);
	}
	return 0;
}

-숨바꼭질(6118, Baekjoon)

1번 농장에서부터 가장 멀리떨어져있는 농장까지의 최소 거리와 농장의 번호를 구하고, 그 농장과 같은 거리를 갖는 농장의 개수를 구해야한다. 1번에서 시작한다. 즉 시작정점에서부터 다른 정점까지의 최단거리를 구하는 모든 알고리즘을 사용할 수 있으며, 나는 Dijkstra를 이용하여 풀었다.

<소스코드>

더보기
#include <stdio.h>
#include <algorithm>
#include <queue>
#include <vector>

using namespace std;

int n, m;
vector <pair<int, int>> vec[20010];
int dis[20020];

void Dijkstra(int x)
{
	int i, j;
	priority_queue<pair<int, int>> pq;
	pq.push({ 0, x });
	dis[x] = 0;
	while (!pq.empty()) {
		int now_idx = pq.top().second, now_val = -pq.top().first;
		pq.pop();
		if (dis[now_idx] < now_val) continue;
		for (i = 0; i < vec[now_idx].size(); i++) {
			int idx = vec[now_idx][i].first, val = vec[now_idx][i].second + now_val;
			if (dis[idx] > val) {
				dis[idx] = val;
				pq.push({ -val, idx });
			}
		}
	}
}

int main()
{
	int i, j;
	scanf("%d %d", &n, &m);
	for (i = 0; i < m; i++) {
		int x, y;
		scanf("%d %d", &x, &y);
		vec[x].push_back({ y, 1 });
		vec[y].push_back({ x, 1 });
	}
	for (i = 1; i <= n; i++) dis[i] = 2e9;
	Dijkstra(1);
	int ans_idx, ans = -2e9;
	for (i = 1; i <= n; i++) {
		if (dis[i] > ans) {
			ans = dis[i];
			ans_idx = i;
		}
	}
	int cnt = 0;
	for (i = 1; i <= n; i++) if (ans == dis[i]) cnt++;
	printf("%d %d %d", ans_idx, ans, cnt);
	return 0;
}

-이분그래프(1707, Baekjoon)

주어진 그래프가 이분그래프인지 탐색하는 문제로, 직접 인접하는 정점을 다른색으로 칠하며, 다른 인접 정점의 색이 현재 정점의 색과 같다면 바로 NO를 출력하고, 문제없이 모두 칠해진다면 YES를 출력하는 식으로 풀었다.

<소스코드>

더보기
#include <stdio.h>
#include <queue>
#include <vector>

using namespace std;

int k, n, m;
vector <int> vec[20010];
int ans;
int ch[20010];

void BFS(int x)
{
	int i;
	queue<int> q;
	ch[x] = 1;
	q.push(x);
	while (!q.empty()) {
		int now = q.front();
		q.pop();
		int check;
		if (ch[now] == 1) check = 2;
		else check = 1;
		for (i = 0; i < vec[now].size(); i++) {
			int nw = vec[now][i];
			if (ch[nw] == 0) {
				ch[nw] = check;
				q.push(nw);
			}
			if (ch[nw] == ch[now]) {
				ans = -1;
				return;
			}
		}
	}
}

int main()
{
	int i, j;
	scanf("%d", &k);
	while (k--) {
		scanf("%d %d", &n, &m);
		for (i = 0; i < m; i++) {
			int x, y;
			scanf("%d %d", &x, &y);
			vec[x].push_back(y);
			vec[y].push_back(x);
		}
		for (i = 1; i <= n; i++) if(ch[i] == 0) BFS(i);
		if (ans == -1) printf("NO\n");
		else printf("YES\n");
		for (i = 1; i <= n; i++) {
			ch[i] = 0;
			while (!vec[i].empty()) vec[i].pop_back();
		}
		ans = 0;
	}
	return 0;
}

-구슬 찾기(2617, Baekjoon)

예전에 풀었던 KOI수학 문제와 비슷해서, 풀이가 금방 떠올랐다. 주어진 대소관계에서 x가 y보다 클 때, 이를 x -> y 와 y -> x로 각각 저장하여, 그래프를 만든다. 그 후, 상위 노드의 수와 하위 노드의 수를 각각 BFS탐색을 통해 구하여, 가운데 오지못하는 경우((n+1)/2보다 큰 경우) ,cnt를 증가시켜 풀었다.

<소스코드>

더보기
#include <stdio.h>
#include <queue>
#include <vector>

using namespace std;

int n, m;
vector <int> vec1[100], vec2[100];
int dis1[100], dis2[100];
int ch[100];

void BFS1(int x)
{
	int i;
	queue<int> q;
	q.push(x);
	ch[x] = 1;
	while (!q.empty()) {
		int now = q.front();
		q.pop();
		for (auto i : vec1[now]) {
			if (ch[i] == 0) {
				ch[i] = 1;
				q.push(i);
			}
		}
	}
}

void BFS2(int x)
{
	int i;
	queue<int> q;
	q.push(x);
	ch[x] = 1;
	while (!q.empty()) {
		int now = q.front();
		q.pop();
		for (auto i : vec2[now]) {
			if (ch[i] == 0) {
				ch[i] = 1;
				q.push(i);
			}
		}
	}
}

int main()
{
	int i, j;
	scanf("%d %d", &n, &m);
	for (i = 0; i < m; i++) {
		int x, y;
		scanf("%d %d", &x, &y);
		vec1[x].push_back(y);
		vec2[y].push_back(x);
	}
	for (i = 1; i <= n; i++) {
		BFS1(i);
		int cnt = 0;
		for (j = 1; j <= n; j++) if (i != j && ch[j] == 1) cnt++;
		dis1[i] = cnt;
		for (j = 1; j <= n; j++) ch[j] = 0;
	}
	for (i = 1; i <= n; i++) {
		BFS2(i);
		int cnt = 0;
		for (j = 1; j <= n; j++) if (i != j && ch[j] == 1) cnt++;
		dis2[i] = cnt;
		for (j = 1; j <= n; j++) ch[j] = 0;
	}
	int ans = 0;
	int mid = (n + 1) / 2;
	for (i = 1; i <= n; i++) {
		if (mid <= dis1[i] || mid <= dis2[i]) ans++;
	}
	printf("%d", ans);
	return 0;
}

-나누기(21757, Baekjoon) 

굉장이 해매다가 에디토리얼을 보고 풀었다. 생각보다 쉬운 문제라 반성을 좀 했었다.

누적합을 이용하여 푸는 문제였다. 문제를 읽어보면 나올 수 있는 경우는 총 3가지 경우가 있다.

1. 전체구간의 누적합이 4로나누어 떨어지지 않는 경우

2. 전체구간의 누적합이 0인경우

3. 전체구간의 누적합이4로 나누어 떨어지는 경우이다.

1번경우는 각부분의 합이 똑같이 4개의 구간으로 나누는 경우가 있을 수 없음으로, 0이 답이다.

2번 경우는 누적합이 0이 되는 구간의 총 수를 구하여, 이를 3가지 그룹으로 나누는 경우의 수를 수식으로 표현하여 구해준다.

3번경우는 전체구간의 누적합을 4로나눈이 하나의 구간이 되어야함으로, n번 탐색을 해보며, 현재의 누적합의 값을 (전체구간 누적합)/4로 나누어, 몇번째 구간인지를 구한 후, 이가 나누어떨어지며, 1과 4 사이의 수라면, 그전 구간의 값을 더하여 준다.

이렇게 3경우를 모두 처리하여 답을 구하였다.

더보기
#include <stdio.h>

long long n, ans;
long long arr[100010], sum[100010];
long long dp[5], dv;

int main()
{
	long long i, j;
	scanf("%lld", &n);
	for (i = 1; i <= n; i++) {
		scanf("%lld", &arr[i]);
		sum[i] = sum[i - 1] + arr[i];
	}
	dp[0] = 1;
	dv = sum[n] / 4;
	if (sum[n] == 0) {
		long long cnt = 0;
		for (i = 1; i <= n; i++) if(sum[i] == 0) cnt++;
		ans = (cnt - 1) * (cnt - 2) * (cnt - 3) / 6;
	}
	else if (sum[n] % 4 != 0) ans = 0;
	else {
		for (i = 1; i <= n; i++) {
			long long res = sum[i] / dv;
			if (sum[i] % dv != 0 || res < 1 || 4 < res) continue;
			dp[res] += dp[res - 1];
		}
		ans = dp[3];
	}
	printf("%lld", ans);
	return 0;
}

'PS(알고리즘 문제풀이) 관련 글 > PS일지' 카테고리의 다른 글

2024-02-29  (0) 2024.02.29
2024-02-28  (1) 2024.02.28
2024-02-27  (2) 2024.02.27
2024-02-26  (2) 2024.02.26
2024-02-25  (0) 2024.02.25