-
Notifications
You must be signed in to change notification settings - Fork 3
/
CCC16S4SecondWay.java
164 lines (138 loc) · 6.15 KB
/
CCC16S4SecondWay.java
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
/**
* CCC '16 S4 - Combining Riceballs
* Question Type: Dynamic Programming
* 15/15 on DMOJ
* Question URL: https://dmoj.ca/problem/ccc16s4
* @author Milliken high school -> http://mmhs.ca/ccc/index.htm
*/
public class CCC16S4SecondWay {
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static StringTokenizer st;
static int [] riceballs;
static int [][] count;
public static void main(String[] args) throws IOException{
int N = Integer.parseInt(br.readLine());
riceballs = new int[N]; count = new int[N][N];
st = new StringTokenizer(br.readLine());
int max = 0;
for (int i = 0; i < N; i++) {
riceballs[i] = Integer.parseInt(st.nextToken());
max = Math.max(riceballs[i], max);
}
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
count[i][j] = -1;
}
}
for (int range=2;range<=N;range++)
{
int maxStart = N-range+1;
for (int firstStartIndex=0;firstStartIndex<maxStart;firstStartIndex++)
{
int lastEndIndex = firstStartIndex + range - 1;
// Search for two block solutions (first,last)
boolean found = search_range_for_two_blocks(firstStartIndex,lastEndIndex);
// If we found a solution with the simple solver don't do any more work
if (found) continue;
// Search for solutions with three blocks (first, middle, last) when we have at least 3 balls
if (range > 2)
search_range_for_three_blocks(firstStartIndex,lastEndIndex);
}
}
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
max = Math.max(max, count[i][j]);
}
}
System.out.println(max);
}
static void add_solution(int startIndex, int endIndex, int ballCount)
{
count[startIndex][endIndex] = ballCount;
}
static boolean can_be_combined(int startIndex, int endIndex)
{
if (startIndex == endIndex)
return true;
else
return count[startIndex][endIndex] != -1;
}
static int get_range_count(int startIndex, int endIndex)
{
if (startIndex == endIndex)
return riceballs[startIndex];
else
return count[startIndex][endIndex];
}
static boolean search_range_for_two_blocks(int firstStartIndex, int lastEndIndex)
{
for (int lastStartIndex = firstStartIndex+1; lastStartIndex <= lastEndIndex; lastStartIndex++)
{
// Define the first range
int firstEndIndex = lastStartIndex-1;
// Skip starting ranges that cannot be combined
if (!can_be_combined(firstStartIndex, firstEndIndex))
continue;
// Skip ending ranges that cannot be combined
if (!can_be_combined(lastStartIndex, lastEndIndex))
continue;
// We need to know the first range count
int firstCount = get_range_count(firstStartIndex,firstEndIndex);
// We need to know the last range count
int lastCount = get_range_count(lastStartIndex,lastEndIndex);
// We can only combine if the first range count is the same as the last range count
if (firstCount != lastCount)
continue;
// Compute the combined number of rice balls
int rangeCount = firstCount + lastCount;
// We have found a solution - lets add it to the our DP container
add_solution(firstStartIndex,lastEndIndex,rangeCount);
// Only one solution is important - we don't have to keep looking for another
return true;
}
// We did not find a solution
return false;
}
static void search_range_for_three_blocks(int firstStartIndex, int lastEndIndex)
{
for (int middleStartIndex = firstStartIndex+1; middleStartIndex < lastEndIndex; middleStartIndex++)
{
// Define the end of the first block
int firstEndIndex = middleStartIndex-1;
// Skip first range if it cannot be combined
if (!can_be_combined(firstStartIndex, firstEndIndex))
continue;
// We need to know the starting range count
int firstCount = get_range_count(firstStartIndex,firstEndIndex);
for (int lastStartIndex = middleStartIndex+1; lastStartIndex <= lastEndIndex; lastStartIndex++)
{
// Define the end of them middle block
int middleEndIndex = lastStartIndex -1;
// Skip middle range that cannot be combined
if (!can_be_combined(middleStartIndex, middleEndIndex))
continue;
// Skip last range that cannot be combined
if (!can_be_combined(lastStartIndex, lastEndIndex))
continue;
// We need to know the last range count
int lastCount = get_range_count(lastStartIndex,lastEndIndex);
// We can only combine if the first range count is the same as the last range count
if (firstCount != lastCount)
continue;
// We need the middle range count so we can compute the full range count
int middleCount = get_range_count(middleStartIndex,middleEndIndex);
int rangeCount = firstCount + middleCount + lastCount;
// We have found a solution - lets add it to the our DP container
add_solution(firstStartIndex,lastEndIndex,rangeCount);
// Only one solution is important - we don't have to keep looking for another
return;
}
}
}
}