-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy path2015 S5 - Greedy For Pies.cpp
140 lines (94 loc) · 4.23 KB
/
2015 S5 - Greedy For Pies.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/*
2015 S5 - Greedy For Pies
Difficulty: Hard
This is a dynammic programming problem, here's the main idea:
As with any DP problem, it's basically just optimized brute force
Meaning we have to try every possible arrangement of pies
And every possible way of choosing pies for each arrangement
To accomplish this, we do not actually need to merge the two arrays
Notice that when inserting the pies from the M line, we would use a pie for one of 2 things
1. To use it as a seperator, if this is the case, we would want to choose the lowest value pie that's left from line M
2. Actually take this pie for its sugar, in this case, we'd want to choose the highest sugar pie that's left from Line M
Therefore, we will sort the M line from least to greatest and maintain 2 iterators
1 on the left that tells us the lowest sugar pie remaining, and 1 on the right that tells us the highest sugar pie remaining
We will now make a 4-D DP array that will indicate the unique state of a scenario
DP [i][j][k][l] tells us that we're at index i of the N pies, j is the left iterator of the M line, k is the right iterator of the M line, and l tells us whether or not we have previously taken a pie
Now that we have a way of representing the state of a scenario, now comes the logic/casework to deciding what to do to reach the next state
Main Case #1 - We've previously taken a pie
Here we cannot take another pie, therefore we can either skip the N pie
Or we can use a pie from the M line as a seperator
Main Case #2 - We haven't taken a pie previously
Here we can choose the pie from the N line
Choose a pie from the M line
Or we can choose to skip the current pie in the N line, imagine the case 999 1 1 999999 (here we need to skip 2 to reach optimal)
Note that if we've reached the end of the N line, we can only access the M line
If both have been exhausted, return our result
Essentially, work backwards with DP
*/
#include <iostream>
#include <vector>
#include <algorithm>
#include <string.h>
#define vi std::vector<int>
#define IMPOSSIBLE -1
const int MAX_N = 3001, MAX_M = 102;
int N, M;
vi A, B; //Sugar of each pie
int DP [MAX_N][MAX_M][MAX_M][2]; //DP array
int solve (int nPie, int leftM, int rightM, bool prevTake){
//Use memoized info if it exists
if (DP[nPie][leftM][rightM][prevTake] > IMPOSSIBLE){
return DP[nPie][leftM][rightM][prevTake];
}
int maxSugar = 0;
//If we've used all pies
if (nPie == N && leftM > rightM){
DP[nPie][leftM][rightM][prevTake] = maxSugar;
return maxSugar;
}
//If previously took a pie
if (prevTake == true){
//If not at the end of the line, we can just skip this pie
if (nPie < N){
maxSugar = std::max(maxSugar, solve(nPie + 1, leftM, rightM, false));
}
//Use seperator pie from M line
if (leftM <= rightM){
maxSugar = std::max(maxSugar, solve(nPie, leftM + 1, rightM, false));
}
}
//If you didn't previously take a pie, more options
else{
//If not at the end of the line
if (nPie < N){
//Take the a pie from the N line
maxSugar = std::max(maxSugar, A[nPie] + solve(nPie + 1, leftM, rightM, true));
//Skip this pie
maxSugar = std::max(maxSugar, solve(nPie + 1, leftM, rightM, false));
}
//Take a pie from the M line
if (leftM <= rightM){
maxSugar = std::max(maxSugar, B[rightM] + solve(nPie, leftM, rightM - 1, true));
}
}
DP[nPie][leftM][rightM][prevTake] = maxSugar;
return maxSugar;
}
int main(){
std::cin >> N;
A.resize(N);
for (int i = 0; i < N; i++){
std::cin >> A[i];
}
std::cin >> M;
B.resize(M + 1);
//NOTE! VERY IMPORTANT YOU USE 1 INDEXING BECAUSE rightM MAY BECOME -1 WITH ZERO INDEXING IF ONE CHOOSES TO REPEATEDLY PICK PIES FROM THE M LINE
for (int i = 1; i <= M; i++){
std::cin >> B[i];
}
std::sort(B.begin(), B.end());
memset(DP, -1, sizeof(DP)); //-1 just means impossible
//Since we recursive tree goes to the edge and then collapses back, the answer is at index 0 in N, index 1 in M, index M in M, no pie taken yet
std::cout << solve(0, 1, M, false) << '\n';
return 0;
}