ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 2024-02-24
    PS(알고리즘 문제풀이) 관련 글/PS일지 2024. 2. 24. 22:17

    -효율적인 해킹(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
Designed by Tistory.