본문 바로가기

ps(알고리즘)

(32)
최솟값과 최댓값 그냥 세그먼트 트리로 최소트리, 최대트리 구현하면 끝나는 문제이다.#include#includeusing namespace std;long long arr[100004];long long max_seg[300004],min_seg[300004];int N,M;void max_init(int n, int s, int e){ if(s==e) { max_seg[n] = arr[s]; return; } int m = (s+e)/2; max_init(n*2,s,m); max_init(n*2+1,m+1,e); max_seg[n] = max(max_seg[n*2],max_seg[n*2+1]); return;}long long min_init(int ..
k번째 수 1 2 3 2 4 6  3 6 9 1 2 2 3 3 4 6 6 N이 3일 때는 이렇게 B 배열이 작성된다.B의 k번째 수를 구해야 한다.즉, A에 있는 N제곱개의 숫자 중에서 k번째로 작은 수를 구하는 문제이다.그냥 N제곱 크기의 배열을 만들어서 정렬을 해버리면 N^2 * 2logN의 시간이 걸려서 애매하다.시간이 되더라도 어차피 N^2 크기의 배열을 만들 메모리가 없기 때문에 안된다. 다른 방법을 찾아야 한다.어떤 숫자를 정하고 그 숫자가 몇번째로 작은 수인지 구하는 과정은 N의 시간만에 할 수 있다.그럼 그 숫자가 x번째로 작은 수라고 가정하고 x가 k보다 작으면 숫자를 키우고, k보다 크면 숫자를 줄이면 된다.즉, 이분탐색으로 해결할 수 있다.long long bin_search(long long ..
구슬 탈출 2 그냥 간단한 dfs/bfs 문제이다. dfs로 풀어도 되겠지만 10번 이하로 구슬을 빼내야 하는 조건이 있길래 bfs로 풀어봤다.#include#includeusing namespace std;int board[100][100]; //.은 0, #는 1, O는2int N,M;int ans = 0;struct state{ int rx,ry,bx,by,num;};int wx[4]={0,0,1,-1};int wy[4]={1,-1,0,0};queueescape;state mov(int i, state curr){ int bc=0,rc=0; while(board[curr.bx][curr.by]==0) { curr.bx+=wx[i]; curr.by+=wy[i]; ..
구간 합 구하기 중간에 수를 바꾸고 구간 합을 구하는 문제이다.그냥 세그먼트 트리를 쓰면 바로 풀린다.#includeint N, M, K;long long arr[1000004];long long sum[3000004];long long init(int n, int s, int e){ if(s==e) return sum[n] = arr[s]; int m = (s+e)/2; return sum[n] = init(n*2, s, m) + init(n*2+1, m+1, e);}long long fin(int n, int s, int e, int fs, int fe){ if(efe) return 0; if(fse) return; sum[n] += diff; if(s!=e) { ..
공항 이것도 그리디적인 해결 방법이 들어가는데, 1~g(i)번째 게이트중 하나에 도킹해야 한다면, g(i)부터 보면서 갈 수 있는 게이트 중최대한 큰 번호의 게이트에 도킹해야 한다.그런데 이걸 그냥 단순 for문으로 구현하면, 최대 g(i)번 탐색을 해야 하니까 시간복잡도가 GP가 되기 때문에 안된다.따라서 도킹을 하면 했다고 체크를 하고, 번호를 탐색하면서 최대 번호를 찾는 방식 말고 다른 방식을 사용해야 한다.g(i)가 들어왔을 때 결국 1~g(i)중 남아있는 번호의 최대를 구해야 한다. 이를 잘 생각해보면 한가지 알고리즘이 떠오른다.세그먼트 트리를 이용하면, 구간별로 max값을 쉽게 탐색할 수도 있고 update도 빠르게 할 수 있다.#include#includeusing namespace std;int..
빵집 dfs와 그리디 알고리즘이 합쳐진 문제이다.왼쪽에서 오른쪽으로 이동을 하는데 왼쪽의 R개의 점에 대해서 다 탐색을 해봐야 한다.여기서 그리디를 적용해야 하는데 길이 겹치면 안되기 때문에 길 하나를 찾아도 최대한 나머지 길들에 영향을 주지 않아야 한다.즉, 위에서부터 (1,1)부터 (R,1)까지 R번의 dfs를 도는데 최대한 위로 가야 아래쪽에서 영향을 안 받는다.오른쪽 위, 오른쪽, 오른쪽 아래 순으로 탐색을 해 나가면 된다.int main(){ scanf("%d %d",&R,&C); for(int i=1;iarr 배열 안에 건물의 상태를 담고, dfs를 왼쪽 시작점들에 대해서 탐색한다.int path[504];int wx[3]={-1,0,1},wy[3]={1,1,1};bool dfs(int ..
저울 저울들을 합쳐서 만들 수 없는 무게를 구하면 된다.간단하게 풀 수 있는데 그냥 무게들을 정렬해 놓고 작은 것부터 더해 나가다가 다음 무게가 이전까지의 모든 무게의 합보다 커버리면 무게의 합+1부터는 만들 수 없다고 판단하면 된다.좀 더 자세히 설명해보자면, 작은것부터 큰것까지 무게들을 정렬했을 때 1번째부터 n번째 무게까지의 합을 sum_n이라고 하자.그리고 1,2,3,...., sum_n은 전부 다 만들 수 있다고 가정하자.이 때 sum_n보다 n+1번째 무게가 작다면, sum_n과 n+1번째 무게의 합 즉, 1부터 sum_(n+1) 까지도 전부 다 만들 수 있다.(1,2,3,..., sum_n을 만들 수 있다고 가정했기 때문에 n+1번째 무게에 1,2,..., sum_n을 더하면 되기 때문)만약 su..
친구 네트워크 친구 관계가 추가될 때마다 그룹에 몇 명이 있는지 출력해야 하기 때문에 그룹에 몇 명이 있는지 탐색하는 과정을 F번 반복해야 한다.일일이 다 친구들과의 관계를 탐색하는 식으로 하면 시간 복잡도가 최소 F제곱이어서 불가능하다. union-find 알고리즘을 쓰면 이를 해결할 수 있다.#include#include#includeusing namespace std;map friends;int group[300004];int gsize[300004];int fin(int x){ if(x==group[x]) return x; return fin(group[x]);}int uni(int a, int b){ int ga = fin(a); int gb = fin(b); if(ga != gb)..