본문 바로가기

ps(알고리즘)

(44)
히스토그램에서 가장 큰 직사각형 앞에서 본 히스토그램과 같은 문제이다.이전에는 스택으로 풀었으니 이번에는 세그먼트 트리로 풀어볼 것이다.구현은 좀 더 복잡하지만 개인적으로 직관적인 이해는 세그트리 방식이 더 쉬웠던거 같다.간단하게 그냥 구간에서 높이가 최소인 곳을 찾고 그 점을 기준으로 왼쪽, 오른쪽에서 넓이가 최대인 직사각형과을 비교하면 된다.구간의 왼쪽에서의 최대넓이, 구간의 오른쪽에서의 최대넓이, 기준점의 높이*구간의 길이 이렇게 3개의 값을 비교해서 최대를 찾으면 끝난다.#include#includeusing namespace std;long long arr[100004];int N;long long big = 1000000005;struct Data{ long long ind,val; bool operatorfe) ..
히스토그램 직사각형들의 높이가 주어졌을 때 가장 큰 넓이의 직사각형을 구하면 된다.두가지 풀이가 있는데 이번에는 스택을 이용해서 풀고 다음에 다른 풀이로 풀어보겠다. 스택을 이용해서 앞에서부터 높이를 하나씩 볼 때 새로 들어온 높이 값이 이전 높이보다 크면 스택에 높이를 넣어준다.이전 높이보다 작으면 이전의 더 큰 높이들은 앞으로의 직사각형에 영향을 미치지 않기 때문에 지금 새로 들어온 높이보다 작아질 때까지 스택에서 pop을 해주면서 직사각형의 넓이들을 구한다.#include#includeusing namespace std;int N;long long ans=0;long long arr[3000004];stack st;int main(){ scanf("%d",&N); st.push(0); for(..
제곱 ㄴㄴ수 에라토스테네스의 체 원리를 이용한 간단한 문제이다.그냥 min부터 max까지 돌면서 sqrt(max)보다 작은 값들의 제곱수로 나눠 떨어지는 수들을 하나씩 제외하면 된다.이미 제외한 수들을 중복해서 제거하지 않기 위해 check 배열을 만드는데 이 배열로 체크할 때 인덱스를 min으로 빼야 배열 크기를 줄일 수 있다. (안 빼면 인덱스가 최대 max까지 늘어나야 해서 불가능)#include#include#includeusing namespace std;long long minv, maxv;int check[1000004];int main(){ scanf("%lld %lld",&minv,&maxv); int arrange = int(sqrt(maxv)); long long ans = max..
외판원 순회 모든 가능한 경로를 탐색하면 최대 16!의 시간이 걸려서 시간초과가 뜰 것이다.더 효율적으로 처리하기 위해서 dp를 쓸 것이다.현재까지 방문한 노드의 상태를 2진법 16자리수로 비트마스킹을 하고, 현재 방문한 점을 이용해서dp[state][current] 이런식으로 쓸 것이다.만약 이 dp값이 존재하며 그 이후는 탐색이 필요하지 않기 때문에 시간을 줄일 수 있다.탐색은 dfs로 돌리면 된다.#include#include#includeusing namespace std;int N;int w[100][100];int dp[100000][100];int big = 100000000;int dfs(int state, int curr){ //printf("%d %d\n",state,curr); if(d..
최솟값과 최댓값 그냥 세그먼트 트리로 최소트리, 최대트리 구현하면 끝나는 문제이다.#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) { ..