본문 바로가기
알고리즘

백준 g4 1806 부분합 c++

by kyj0032 2024. 2. 29.

https://www.acmicpc.net/problem/1806

 

1806번: 부분합

첫째 줄에 N (10 ≤ N < 100,000)과 S (0 < S ≤ 100,000,000)가 주어진다. 둘째 줄에는 수열이 주어진다. 수열의 각 원소는 공백으로 구분되어져 있으며, 10,000이하의 자연수이다.

www.acmicpc.net

 

문제

길이가 N인 수열이 주어지고, 연속된 수들의 부분합이 S 이상이 되는 것 중 가장 짧은 것의 길이 구하기

 

풀이

 

만약 그냥 이중 for문으로 구현해본다면

for i: 0 ~ N-1
	for j: i+1 ~ N-1
    	if sum >= S
        	min 갱신
        else
        	sum += a[j]
            len++

 

이걸 투포인터로 바꿔보기

 

st, en이 주어지고, st ~ en까지 더한다고 생각하자.

 

1) sum >= S 일 때까지 en++

2) 조건 만족하면 st++

 

여기서 고민했던 건 2가지였다.

1. st++하면 새로운 시작점에서 새로운 합이 시작되는 거랑 똑같은데, en의 커서도 --해서 최적값을 찾아야할까?

- en까지 더해서 겨우 S를 넘었는데 st++을 하게 되면 오히려 sum -= arr[st] 이므로 수가 더 작아진다. en--할 필요 없음

2. en이 수열 끝까지 도달한 경우

- 이 다음은 st++로 sum이 줄어드는 일 밖에 없으므로, 그냥 break 해도 됨

- en == N-1일 땐 if sum >= S 에 걸려서 min을 갱신함.

- 반면에 en == N 일 땐 sum이 부족해서 en을 더 더해야하는 상황이라 어차피 답이 될 수 없음.

 

수도 코드

 

while st != N && en != N
	if sum >= S
    	ans 갱신, 
        
        sum -= st빼기
        st++
        len--
    else
    	en++
        sum += en더하기
        len++

 

 

 전체 코드

/*boj g4 1806 부분합*/
#include <iostream>
#define MAXN 100005
using namespace std;

int N, S;
int arr[MAXN];
int main(void) {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >> N >> S;
    for (int i = 0; i < N; i++)
        cin >> arr[i];

    int st = 0;
    int en = -1;

    int sum = 0;
    int len = 0;
    int ans = 100010;
    while (st != N && en != N) {
        if (sum >= S) {
            ans = min(ans, len);

            sum -= arr[st];
            st++;
            len--;
            continue;
        } else {
            en++;
            sum += arr[en];
            len++;
        }
    }
    if (ans == 100010) ans = 0;
    cout << ans << "\n";
}

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

백준 s1 2531 회전 초밥 c++  (0) 2024.03.02
백준 s4 2003 수들의 합 2 c++  (0) 2024.03.01
백준 g5 2230 수 고르기 c++  (0) 2024.02.29
SQL 정리  (0) 2024.02.28
백준 g4 2110 공유기 설치 c++  (0) 2024.02.28