Back and Forth
Solución en video
Por Jonathan Paulson
Video de YouTube (yzPV0NZAUV4)
Código de la solución en video
#include <cassert>
#include <cstdio>
#include <iostream>
#include <set>
#include <vector>
using namespace std;
using ll = int64_t;
// Las cantidades posibles que podrían quedar en el tanque del primer establo
set<ll> possible;
void solve(ll trips_left, const vector<ll> &buckets_here,
const vector<ll> &buckets_there, ll tank_here, ll tank_there) {
if (trips_left == 0) {
// Completamos todos los viajes, así que la cantidad actual en el tanque del
// primer establo es posible. Empezamos en el primer establo e hicimos cuatro
// viajes, así que también terminamos en el primer establo, así que @tank_here representa
// la cantidad en el tanque del primer establo
possible.insert(tank_here);
} else {
for (ll taken_idx = 0; taken_idx < buckets_here.size(); taken_idx++) {
ll bucket = buckets_here[taken_idx];
// Dejamos el balde tomado en el destino
vector<ll> new_buckets_dest(buckets_there);
new_buckets_dest.push_back(bucket);
// Sacamos el balde tomado de nuestro establo actual
vector<ll> new_buckets_src;
for (ll i = 0; i < buckets_here.size(); i++) {
if (i != taken_idx) { new_buckets_src.push_back(buckets_here[i]); }
}
// Movemos @bucket galones de leche del tanque actual al
// otro tanque
ll new_tank_dest = tank_there + bucket;
ll new_tank_src = tank_here - bucket;
// Como fuimos al otro establo, "here" ahora se refiere al establo
// "dest" y "there" ahora se refiere al establo "src"
solve(trips_left - 1, new_buckets_dest, new_buckets_src, new_tank_dest,
new_tank_src);
}
}
}
int main() {
assert(freopen("backforth.in", "r", stdin) != nullptr);
assert(freopen("backforth.out", "w", stdout) != nullptr);
vector<ll> buckets_here;
for (ll i = 0; i < 10; i++) {
ll bucket;
cin >> bucket;
buckets_here.push_back(bucket);
}
vector<ll> buckets_there;
for (ll i = 0; i < 10; i++) {
ll bucket;
cin >> bucket;
buckets_there.push_back(bucket);
}
solve(4, buckets_here, buckets_there, 1000, 1000);
cout << possible.size() << endl;
}import java.io.*;
import java.util.*;
public class backforth {
// Las cantidades posibles que podrían quedar en el tanque del primer establo
static HashSet<Integer> possible = new HashSet<Integer>();
static void solve(int trips_left, ArrayList<Integer> buckets_here,
ArrayList<Integer> buckets_there, int tank_here, int tank_there) {
if (trips_left == 0) {
// Completamos todos los viajes, así que la cantidad actual en el tanque
// del primer establo es posible. Empezamos en el primer establo e
// hicimos cuatro viajes, así que también terminamos en el primer establo, así que @tank_here
// representa la cantidad en el tanque del primer establo
possible.add(tank_here);
} else {
for (int taken_idx = 0; taken_idx < buckets_here.size(); taken_idx++) {
int bucket = buckets_here.get(taken_idx);
// Dejamos el balde tomado en el destino
ArrayList<Integer> new_buckets_dest =
new ArrayList<Integer>(buckets_there);
new_buckets_dest.add(bucket);
// Sacamos el balde tomado de nuestro establo actual
ArrayList<Integer> new_buckets_src = new ArrayList<Integer>();
for (int i = 0; i < buckets_here.size(); i++) {
if (i != taken_idx) { new_buckets_src.add(buckets_here.get(i)); }
}
// Movemos @bucket galones de leche del tanque actual al
// otro tanque
int new_tank_dest = tank_there + bucket;
int new_tank_src = tank_here - bucket;
// Como fuimos al otro establo, "here" ahora se refiere al
// establo "dest" y "there" ahora se refiere al establo "src"
solve(trips_left - 1, new_buckets_dest, new_buckets_src, new_tank_dest,
new_tank_src);
}
}
}
public static void main(String[] args) throws Exception {
BufferedReader in = new BufferedReader(new FileReader("backforth.in"));
PrintWriter out =
new PrintWriter(new BufferedWriter(new FileWriter("backforth.out")));
String[] first_barn = in.readLine().split(" ");
String[] second_barn = in.readLine().split(" ");
ArrayList<Integer> buckets_here = new ArrayList<Integer>();
for (int i = 0; i < 10; i++) {
buckets_here.add(Integer.parseInt(first_barn[i]));
}
ArrayList<Integer> buckets_there = new ArrayList<Integer>();
for (int i = 0; i < 10; i++) {
buckets_there.add(Integer.parseInt(second_barn[i]));
}
solve(4, buckets_here, buckets_there, 1000, 1000);
out.println(possible.size());
out.flush();
}
}# Las cantidades posibles que podrían quedar en el tanque del primer establo
possible = set()
def solve(trips_left, buckets_here, buckets_there, tank_here, tank_there):
if trips_left == 0:
# Completamos todos los viajes, así que la cantidad actual en el tanque del primer establo es posible
# Empezamos en el primer establo e hicimos cuatro viajes, así que también terminamos en el primer establo,
# así que @tank_here representa la cantidad en el tanque del primer establo
possible.add(tank_here)
else:
for taken_idx, bucket in enumerate(buckets_here):
# Dejamos el balde tomado en el destino
new_buckets_dest = buckets_there + [bucket]
# Sacamos el balde tomado de nuestro establo actual
new_buckets_src = [b for i, b in enumerate(buckets_here) if i != taken_idx]
# Movemos @bucket galones de leche del tanque actual al otro tanque
new_tank_dest = tank_there + bucket
new_tank_src = tank_here - bucket
# Como fuimos al otro establo, "here" ahora se refiere al establo "dest" y
# "there" ahora se refiere al establo "src"
solve(
trips_left - 1,
new_buckets_dest,
new_buckets_src,
new_tank_dest,
new_tank_src,
)
first_barn, second_barn = open("backforth.in").readlines()
buckets_here = [int(x) for x in first_barn.split()]
buckets_there = [int(x) for x in second_barn.split()]
# Terminamos haciendo 4 viajes de ida y vuelta
# Cada tanque empieza con 1000 galones de leche
# Es imposible quedarse sin leche en alguno de los tanques,
# ya que solo hacemos 4 viajes y cada balde guarda como máximo 100 galones
solve(4, buckets_here, buckets_there, 1000, 1000)
with open("backforth.out", "w") as fout:
print(len(possible), file=fout)Pista 1
¿Qué información necesitamos cuando Farmer John llega a un establo?
Respuesta a la Pista 1
Hay que conocer el día, los baldes disponibles en cada establo y las cantidades actuales de los tanques.
Pista 2
En cada momento, podríamos elegir cualquier balde para mover. ¿Podríamos escribir una lógica general para manejar todos estos estados posibles?
Solución
Solución
Similar a la segunda solución del análisis.
#include <bits/stdc++.h>
using namespace std;
set<int> possible;
void get_possible(int day, int a_tank, vector<int> a_buckets, int b_tank,
vector<int> b_buckets) {
// Último día, agregamos la cantidad de leche del primer tanque.
if (day == 4) {
possible.insert(a_tank);
return;
}
// Esto transfiere cada balde posible del establo x al establo y.
for (int i = 0; i < a_buckets.size(); i++) {
// Balde a transferir.
int t = a_buckets[i];
// Creamos una copia nueva de los baldes disponibles y transferimos el i-ésimo.
vector<int> new_a = a_buckets;
new_a.erase(begin(new_a) + i);
vector<int> new_b = b_buckets;
new_b.push_back(t);
// Llamamos recursivamente a la función con los nuevos baldes y cantidades de tanque.
get_possible(day + 1, b_tank + t, new_b, a_tank - t, new_a);
}
}
int main() {
freopen("backforth.in", "r", stdin);
freopen("backforth.out", "w", stdout);
vector<int> a(10);
for (int &i : a) { cin >> i; }
vector<int> b(10);
for (int &i : b) { cin >> i; }
get_possible(0, 1000, a, 1000, b);
cout << possible.size() << endl;
}import java.io.*;
import java.util.*;
public class BackForth {
static Set<Integer> possible = new HashSet<>();
public static void main(String[] args) throws IOException {
BufferedReader read = new BufferedReader(new FileReader("backforth.in"));
StringTokenizer aST = new StringTokenizer(read.readLine());
StringTokenizer bST = new StringTokenizer(read.readLine());
List<Integer> a = new ArrayList<>();
List<Integer> b = new ArrayList<>();
for (int i = 0; i < 10; i++) {
a.add(Integer.parseInt(aST.nextToken()));
b.add(Integer.parseInt(bST.nextToken()));
}
getPossible(0, 1000, a, 1000, b);
PrintWriter write = new PrintWriter("backforth.out");
write.println(possible.size());
write.close();
}
static void getPossible(int day, int aTank, List<Integer> aBuckets, int bTank,
List<Integer> bBuckets) {
// Último día, agregamos la cantidad de leche del primer tanque.
if (day == 4) {
possible.add(aTank);
return;
}
// Esto transfiere cada balde posible del establo x al establo y.
for (int i = 0; i < aBuckets.size(); i++) {
// Balde a transferir.
int t = aBuckets.get(i);
// Creamos una copia nueva de los baldes disponibles y transferimos el
// i-ésimo.
List<Integer> newA = new ArrayList<>(aBuckets);
newA.remove(i);
List<Integer> newB = new ArrayList<>(bBuckets);
newB.add(t);
// Llamamos recursivamente a la función con los nuevos baldes y
// cantidades de tanque.
getPossible(day + 1, bTank + t, newB, aTank - t, newA);
}
}
}import sys
from typing import List
sys.stdin = open("backforth.in", "r")
sys.stdout = open("backforth.out", "w")
possible = set()
def get_possible(
day: int, a_tank: int, a_buckets: List[int], b_tank: int, b_buckets: List[int]
) -> None:
# Último día, agregamos la cantidad de leche del primer tanque.
if day == 4:
possible.add(a_tank)
return
# Esto transfiere cada balde posible del establo x al establo y.
for i in range(len(a_buckets)):
# Balde a transferir.
t = a_buckets[i]
# Creamos una copia nueva de los baldes disponibles y transferimos el i-ésimo.
new_a = a_buckets.copy()
del new_a[i]
new_b = b_buckets.copy()
new_b.append(t)
# Llamamos recursivamente a la función con los nuevos baldes y cantidades de tanque.
get_possible(day + 1, b_tank + t, new_b, a_tank - t, new_a)
a = list(map(int, input().split()))
b = list(map(int, input().split()))
get_possible(0, 1000, a, 1000, b)
print(len(possible))