summary refs log tree commit diff
path: root/22.16/main.cpp
blob: 62ffe2a328435bfd786fa78250ca573ac8a074f3 (plain)
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
#include <algorithm>
#include <deque>
#include <iostream>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
using namespace std;

int parseID(string s) {
	return (s[0] - 'A') * ('Z' - 'A' + 1) + (s[1] - 'A');
}

// Fucking hell.
struct hash_pair {
	template<typename T1, typename T2>
	size_t operator()(const pair<T1, T2>& p) const
	{
		auto h1 = hash<T1>{}(p.first);
		auto h2 = hash<T1>{}(p.second);
		return h1 ^ (h2 << 1);
	}
};

struct Graph {
	unordered_multimap<int, int> conns;
	unordered_map<int, int> rates;

	unordered_map<pair<int, int>, int, hash_pair> dist;
};

void findLengths(Graph &g, int base) {
	deque<int> frontier;
	frontier.push_back(base);
	g.dist.insert({{base, base}, 0});
	while (!frontier.empty()) {
		// i love c++ i love c++ i love c++
		int from = frontier.front();
		int dist = g.dist[{base, from}];
		frontier.pop_front();
		auto range = g.conns.equal_range(from);
		for (auto it = range.first; it != range.second; it++) {
			int to = it->second;
			if (g.dist.count({base, to}) != 0)
				continue;
			g.dist.insert({{base, to}, dist + 1});
			frontier.push_back(to);
		}
	}
}

Graph g;

int rec(vector<int> &avail, int time1, int time2, int score = 0, int pos1 = 0, int pos2 = 0) {
	int best = score;
	if (time1 < time2) {
		swap(time1, time2);
		swap(pos1, pos2);
	}
	for (int i = 0; i < avail.size(); i++) {
		int n = avail[i];
		if (n == 0) continue;

		int time1_b = time1 - g.dist[{pos1, n}] - 1;
		if (time1_b > 0) {
			avail[i] = 0;
			int score_b = score + g.rates[n] * time1_b;
			best = max(best, rec(avail, time1_b, time2, score_b, n, pos2));
			avail[i] = n;
		}
	}
	return best;
}

int main() {
	vector<int> nonzero;
	for (string s; getline(cin, s); ) {
		auto numStart = s.find('=') + 1;
		auto numEnd = s.find(';', numStart) - numStart;

		int from = parseID(s.substr(6, 2));
		int rate = stoi(s.substr(numStart, numEnd));

		g.rates[from] = rate;
		if (rate != 0) nonzero.push_back(from);

		s = s.substr(s.find(' ', s.find("valve")) + 1);
		for (int i = 0; i + 2 <= s.size(); i += 4) {
			int to = parseID(s.substr(i, 2));
			g.conns.insert({from, to});
		}
	}

	findLengths(g, 0);
	for (int base : nonzero)
		findLengths(g, base);

	cout << rec(nonzero, 30, 0) << endl;
	cout << rec(nonzero, 26, 26) << endl;
}