Snakes
USACO 2019 US Open Contest, Gold - Problem 1. Snakes
Algorithm
DP on the location in the line where we start, the number of net switches remaining and the current net size.
Given a certain location x
, number of switches i
, and net size s
:
- If we have no net size switches left, then the optimal solution is the difference between the net size and the number of snakes at
x
, plus the optimal solution of the next location with the current net size and zero switches, ordp[x+1][0][s] + diff
. - Otherwise, we have two choices:
- Use one net size switch. Then the solution is the minimum of all
dp[x+1][i-1] + diff
. - Keep the current number of net size switches. Then the solution is
dp[x+1][i-1][s] + diff
.
- Use one net size switch. Then the solution is the minimum of all
Once we have constructed the DP table, our answer is the minimum of the dp[0][k]
(where k
is the maximum number of net switches).
C++
#include <bits/stdc++.h>
#include <cstdio>
using namespace std;
void setio(string s) {
freopen((s+".in").c_str(),"r",stdin);
freopen((s+".out").c_str(),"w",stdout);
}
int main() {
int inf = 1e9;
freopen("snakes.in","r",stdin);
freopen("snakes.out","w",stdout);
// Get input
// setio("snakes");
int n, k;
cin >> n >> k;
vector<int> snakes;
for (int i=0; i<n; i++) {
int x;
cin >> x;
snakes.push_back(x);
}
vector<int> sortedSnakes = snakes;
sort(sortedSnakes.begin(), sortedSnakes.end());
// Tabulation
/* dp[x][i][s] where
x is the starting location,
i is the number of switches,
s is the current net size
*/
int dp[401][301][401];
int minRow[401][301];
// Fill bottom row
for (int s=0; s<n; ++s) {
for (int i=0; i<k+1; ++i) {
int diff = sortedSnakes[s] - snakes[n-1];
if (diff >= 0) {
dp[n-1][i][s] = diff;
}
else {
dp[n-1][i][s] = inf;
}
}
}
// Run DP
for (int x=n-2; x>=0; --x) {
for (int i=0; i<k+1; ++i) {
int m = inf;
for (int j=0; j<n; ++j) {
if (dp[x+1][i][j] < m) {
m = dp[x+1][i][j];
};
}
minRow[x+1][i] = m;
//cout << m << endl;
}
for (int s=0; s<n; ++s) {
// x = the current location in the line
// s = the number of net switches remaining
int diff = sortedSnakes[s] - snakes[x];
if (diff >= 0) { // Possible to catch snakes with current net
if (dp[x+1][0][s] != inf) {
dp[x][0][s] = dp[x+1][0][s] + diff; // set zero column
}
else {
dp[x][0][s] = inf;
}
for (int i=1; i<=k; ++i) {
// switch net, or don't
dp[x][i][s] = min(minRow[x+1][i-1], dp[x+1][i][s]) + diff;
}
}
else {
for (int i=0; i<=k; ++i) {
dp[x][i][s] = inf;
}
}
}
}
int m = inf;
for (int j=0; j<n; ++j) {
if (dp[0][k][j] < m) {
m = dp[0][k][j];
}
}
cout << m << endl;
return 0;
}