알고리즘/acmicpc
2616
kwony
2015. 10. 3. 00:34
이런 문제가 2003년 초등부 올림피아드에 나왔으니 내가 당시 초등학교 6학년이었으니까,, 감히 이런걸 푼다고 상상도 했을까... 이런 문제를 푸는 괴물들도 있었겠지. 나는 이걸 대학생이 되어서야 풀게 되었다.
이 문제는 DP문제이다. 어떻게 DP를 구현하느냐에 따라서 해결 방법이 천차 만별이다.
총 세개의 기관차를 쓰는게 이 문제를 푸는데 핵심이다.
처음에는 각 구간별로 n개의 소형기관차를 썼을 때 최대 값을 구하는 함수를 사용했다. 하지만 이건 배열을 여러번 탐색해야해서(O(N^n)) 시간초과가 뜬다.
어떻게 해야할지 고민하다가 세개의 기관차를 사용하는 것에서 방법을 찾았다.
먼저 현재 위치에서 소형차기관차를 연결했을 때 태울 수 있는 승객을 저장하는 배열을 만든후 d[0][50000]에 넣어둔다.
그 후 d[1][50000]은 이전 d[0]에 넣은 것들에서 현재 소형 기관차 앞에 있는 객차중 소형기관차를 연결 했을 떄 최대가 되는 것들을 찾는다. 그러면 d[1][50000]은 소형 기관차 두 개를 연결 했을 때 손님의 객수를 최대로 하는 방법이다.
마지막으로 d[2][50000]은 d[1]에 넣은 것들에서 현재 소형기관차 뒤에 있는 객차중 소형기관차를 연결 했을 때 최대가 되는 것들을 찾는다. 이전에 앞에 있는 객차들 중에서 찾았기 때문에 지금은 뒤에있는 것들에서 찾아야 중복이 되지 않는다.
만약 4개의 소형기관차를 사용한다면 위 알고리즘을 사용할 수 없다. 시간초과가 뜬 원래 알고리즘을 사용할 수밖에.
#include<cstdio>
#include<iostream>
#include<fstream>
using namespace std;
int d[3][50000];
int partialSum[50005];
int length;
int N;
int main(){
int tmp;
int res=0;
ifstream ifp("input.txt");
ifp>>N;
//scanf("%d", &N);
for(int i=1; i<=N; i++){
ifp>>tmp;
//scanf("%d", &tmp);
partialSum[i] = partialSum[i-1]+tmp;
}
ifp>>length;
//scanf("%d", &length);
for(int piv=1; piv<=N-length+1; piv++){
d[0][piv]=partialSum[piv+length-1]-partialSum[piv-1];
}
int partialMax=0;
for(int piv=1; piv<=N-length+1; piv++){
int addable = piv-length;
if(addable > 0){
partialMax = max(d[0][addable], partialMax);
}
d[1][piv] = d[0][piv] + partialMax;
}
partialMax = 0;
for(int piv=N-length+1; piv>=1; piv--){
int addable = piv+length;
if(addable <= N-length+1){
partialMax = max(d[0][addable], partialMax);
}
d[2][piv]=d[1][piv] + partialMax;
res = max(res, d[2][piv]);
}
printf("%d\n", res);
return 0;
}