davehill

AoC 2022 day 16

Dec 22nd, 2022
890
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 6.60 KB | None | 0 0
  1. #include "2022_utils.h"
  2.  
  3. #include <unordered_set>
  4.  
  5. using namespace std;
  6.  
  7. namespace {
  8.   struct Valve {
  9.     string name;
  10.     int flow = 0;
  11.     vector<Valve*> edges;
  12.   };
  13.  
  14.   struct State {
  15.     Valve* v;
  16.     unordered_set<Valve*> visited;
  17.     unordered_set<Valve*> opened;
  18.     int total_flow = 0;
  19.     int time = 0;
  20.   };
  21.  
  22.   auto part1() {
  23.     auto in = load_strings("2022/2022_day16_input.txt");
  24.  
  25.     // names and flow
  26.     vector<Valve> v;
  27.     for (auto& s : in) {
  28.       int flow;
  29.       char name[16];
  30.       sscanf_s(s.c_str(), "Valve %s has flow rate = %d",
  31.         name, 16, &flow);
  32.       v.push_back({ .name = name, .flow = flow, });
  33.     }
  34.  
  35.     // edges
  36.     for (int i = 0; i < v.size(); ++i) {
  37.       auto& valve = v[i];
  38.       auto edges = split(in[i], " valves ");
  39.       if (edges.size() == 1) {
  40.         edges = split(in[i], " valve ");
  41.       }
  42.       string edges_str = edges[1];
  43.       for (string e : split(edges_str, ", ")) {
  44.         for (auto& v2 : v) {
  45.           if (v2.name == e) {
  46.             valve.edges.push_back(&v2);
  47.             break;
  48.           }
  49.         }
  50.       }
  51.     }
  52.  
  53.     // Store the top scores for this minute, and stop exploring
  54.     // new ideas if we don't look competitive.
  55.     map<int, vector<int>> best_flows_per_minute;
  56.     const int keep_top_per_minute = 100;
  57.  
  58.     deque<State> q;
  59.     q.push_back({ &v[0] });
  60.  
  61.     int max_flow = 0;
  62.     while (!q.empty()) {
  63.       State state = q.front();
  64.       q.pop_front();
  65.  
  66.       // Add all pressure from opened valves.
  67.       for (Valve* v : state.opened) {
  68.         state.total_flow += v->flow;
  69.       }
  70.  
  71.       state.visited.insert(state.v);
  72.       state.time += 1;
  73.       if (state.time == 30) {
  74.         max_flow = max(state.total_flow, max_flow);
  75.         continue;
  76.       }
  77.  
  78.       // Abandon further exploration if it's not looking good.
  79.       vector<int>& best_flows = best_flows_per_minute[state.time];
  80.       auto it = upper_bound(best_flows.rbegin(), best_flows.rend(), state.total_flow).base();
  81.       if (best_flows.size() >= keep_top_per_minute && it == best_flows.end()) {
  82.         continue;
  83.       }
  84.       best_flows.insert(it, state.total_flow);
  85.       best_flows.resize(min(keep_top_per_minute, (int)best_flows.size()));
  86.  
  87.       // Move.
  88.       bool did_something = false;
  89.       {
  90.         for (Valve* next : state.v->edges) {
  91.           if (!state.visited.contains(next)) {
  92.             auto s_next = state;
  93.             s_next.v = next;
  94.             q.push_back(s_next);
  95.             did_something = true;
  96.           }
  97.         }
  98.       }
  99.  
  100.       // Open valve.
  101.       if (!state.opened.contains(state.v) && state.v->flow > 0) {
  102.         auto s_next = state;
  103.         s_next.opened.insert(state.v);
  104.         s_next.visited.clear();
  105.         q.push_back(s_next);
  106.         did_something = true;
  107.       }
  108.  
  109.       // Do nothing, waste time.
  110.       if (!did_something) {
  111.         q.push_back(state);
  112.       }
  113.     }
  114.  
  115.     return max_flow;
  116.   }
  117.  
  118.   struct State2 {
  119.     Valve* v1;
  120.     Valve* v2; // elephant location.
  121.     unordered_set<Valve*> visited1, visited2;
  122.     unordered_set<Valve*> opened;
  123.     int total_flow = 0;
  124.     int time = 0;
  125.   };
  126.  
  127.   auto part2() {
  128.     auto in = load_strings("2022/2022_day16_input.txt");
  129.  
  130.     // names and flow
  131.     vector<Valve> v;
  132.     for (auto& s : in) {
  133.       int flow;
  134.       char name[16];
  135.       sscanf_s(s.c_str(), "Valve %s has flow rate = %d",
  136.         name, 16, &flow);
  137.       v.push_back({ .name = name, .flow = flow, });
  138.     }
  139.  
  140.     // edges
  141.     for (int i = 0; i < v.size(); ++i) {
  142.       auto& valve = v[i];
  143.       auto edges = split(in[i], " valves ");
  144.       if (edges.size() == 1) {
  145.         edges = split(in[i], " valve ");
  146.       }
  147.       string edges_str = edges[1];
  148.       for (string e : split(edges_str, ", ")) {
  149.         for (auto& v2 : v) {
  150.           if (v2.name == e) {
  151.             valve.edges.push_back(&v2);
  152.             break;
  153.           }
  154.         }
  155.       }
  156.     }
  157.  
  158.     // Store the top scores for this minute, and stop exploring
  159.     // new ideas if we don't look competitive.
  160.     map<int, vector<int>> best_flows_per_minute;
  161.     const int keep_top_per_minute = 100;
  162.  
  163.     deque<State2> q;
  164.     q.push_back(State2{
  165.       .v1 = &v[0],
  166.       .v2 = &v[0], });
  167.  
  168.     int max_flow = 0;
  169.     while (!q.empty()) {
  170.       State2 state = q.front();
  171.       q.pop_front();
  172.  
  173.       // Add all pressure from opened valves.
  174.       for (Valve* v : state.opened) {
  175.         state.total_flow += v->flow;
  176.       }
  177.  
  178.       state.visited1.insert(state.v1);
  179.       state.visited2.insert(state.v2);
  180.       state.time += 1;
  181.       if (state.time == 26) {
  182.         max_flow = max(state.total_flow, max_flow);
  183.         continue;
  184.       }
  185.  
  186.       // Abandon further exploration if it's not looking good.
  187.       vector<int>& best_flows = best_flows_per_minute[state.time];
  188.       auto it = upper_bound(best_flows.rbegin(), best_flows.rend(), state.total_flow).base();
  189.       if (best_flows.size() >= keep_top_per_minute && it == best_flows.end()) {
  190.         continue;
  191.       }
  192.       best_flows.insert(it, state.total_flow);
  193.       best_flows.resize(min(keep_top_per_minute, (int)best_flows.size()));
  194.  
  195.       // Move.
  196.       vector<State2> new_states;
  197.       bool did_something = false;
  198.  
  199.       for (Valve* next : state.v1->edges) {
  200.         if (!state.visited1.contains(next)) {
  201.           auto s_next = state;
  202.           s_next.v1 = next;
  203.           new_states.push_back(s_next);
  204.           did_something = true;
  205.         }
  206.       }
  207.  
  208.       // Open valve.
  209.       if (!state.opened.contains(state.v1) && state.v1->flow > 0) {
  210.         auto s_next = state;
  211.         s_next.opened.insert(state.v1);
  212.         s_next.visited1.clear();
  213.         new_states.push_back(s_next);
  214.         did_something = true;
  215.       }
  216.  
  217.       // Elephant also does something.
  218.       for (State2& state : new_states) {
  219.         // Move
  220.         for (Valve* next : state.v2->edges) {
  221.           if (!state.visited2.contains(next)) {
  222.             auto s_next = state;
  223.             s_next.v2 = next;
  224.             q.push_back(s_next);
  225.             did_something = true;
  226.           }
  227.         }
  228.  
  229.         // Open valve.
  230.         if (!state.opened.contains(state.v2) && state.v2->flow > 0) {
  231.           auto s_next = state;
  232.           s_next.opened.insert(state.v2);
  233.           s_next.visited2.clear();
  234.           q.push_back(s_next);
  235.           did_something = true;
  236.         }
  237.       }
  238.  
  239.       // Do nothing, waste time.
  240.       if (!did_something) {
  241.         q.push_back(state);
  242.       }
  243.     }
  244.  
  245.     return max_flow;
  246.   }
  247. }
  248.  
  249. namespace y2022 {
  250.   void day16() {
  251.     cout << "part 1: " << part1() << "\n";
  252.     cout << "part 2: " << part2() << "\n";
  253.   }
  254. }
  255.  
Advertisement
Add Comment
Please, Sign In to add comment