https://www.acmicpc.net/problem/1806
1806번: 부분합
문제 10,000 이하의 자연수로 이루어진 길이 N짜리 수열이 주어진다. 이 수열에서 연속된 수들의 부분합 중에 그 합이 S 이상이 되는 것 중, 가장 짧은 것의 길이를 구하는 프로그램을 작성하시오. 입력 첫째 줄에 N (10 ≤ N < 100,000)과 S (0 < S ≤ 100,000,000)가 주어진다. 둘째 줄에는 수열이 주어진다. 수열의 각 원소는 공백으로 구분되어져 있으며, 10,000이하의 자연수이다. 출력 첫째 줄에 구하고자 하는 최소의 길
www.acmicpc.net
위 문제를 전체 탐색을 하면 O(N^2)으로 N이 100000이어서 시간초과가 난다.
투 포인터 알고리즘을 이용하여 풀 수 있다. 배열에 연속된 합의 처음과 끝부분을 가리키는 변수를 만들고 이 변수를 움직여서 합을 구하는 것이다.
s = 연속합의 처음 인덱스
e = 연속합의 끝 인덱스 + 1
1. 합이 찾는 값 S보다 크거나 같으면, 합을 수열[s]값을 빼고 s에 1을 더한다.
2. e가 수열의 끝이면 더 이상 합이 커질 수 없어 반복문을 끝낸다
3. 합이 작으면 e에 1을 더하고 합에 수열[e]만큼 더하면 된다.
즉, s, e 포인터를 움직이면서 연속된 합이 S이상일 때 그 길이를 통해 정답을 구하면 된다.
#include <stdio.h>
#include <vector>
#include <algorithm>
#define min(a, b) ((a) < (b)? (a):(b))
using namespace std;
int n, S;
int a[100001];
int ans = 1000000;
int main()
{
scanf("%d%d", &n, &S);
for (int i = 0; i < n; i++)
scanf("%d", a + i);
int s, e;
s = e = 0;
int sum = 0;
while (s <= e)
{
if (sum >= S)
{
sum -= a[s];
s++;
}
else if (e == n) break;
else
{
sum += a[e];
e++;
}
if (sum >= S)
ans = min(ans, e - s);
}
if (ans == 1000000)
ans = 0;
printf("%d", ans);
}'Problem Solving' 카테고리의 다른 글
| [BOJ 1005] ACM Craft (0) | 2020.04.20 |
|---|---|
| [BOJ 1516] 게임 개발 (0) | 2020.04.20 |
| [BOJ 13398] 연속합 2 (0) | 2020.04.17 |
| [BOJ 1717] 집합의 표현 (0) | 2020.04.08 |
| [BOJ 5247] 불 (0) | 2020.04.08 |