Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <cmath>
- #include <cstdio>
- #include <string>
- #include <vector>
- #include <iostream>
- #include <algorithm>
- #include <stack>
- #include <utility>
- #include <map>
- #include <unordered_map>
- #include <deque>
- #include <queue>
- using namespace std;
- int score(const string &s) {
- int r = 0;
- for(const auto &c : s) {
- if(c == 'A' || c == 'E' || c == 'I' || c == 'L' || c == 'N' || c == 'O' || c == 'R' || c == 'S' || c == 'T' || c == 'U') r += 1;
- else if(c == 'D' || c == 'G') r += 2;
- else if(c == 'B' || c == 'C' || c == 'M' || c == 'P') r+= 3;
- else if(c == 'F' || c == 'H' || c == 'V' || c == 'W' || c == 'Y') r += 4;
- else if(c == 'K') r += 5;
- else if(c == 'J' || c == 'X') r += 8;
- else if (c == 'Q' || c == 'Z') r += 10;
- }
- return r;
- }
- using pii = pair<int, deque<int>>;
- int main() {
- size_t K; cin >> K;
- size_t N; cin >> N;
- multimap<string, int> edge_ids;
- vector<vector<int>> edges;
- vector<int> scores;
- // Build graph (ie replcae each character with '_' and attach to all other nodes that have the same hash)
- for(size_t i = 0; i < N; i++) {
- string s; cin >> s;
- if(s.length() != K) continue;
- int id = scores.size();
- scores.push_back(score(s));
- edges.push_back({});
- for(size_t j = 0; j < s.length(); j++) {
- char t = s[j];
- s[j] = '_';
- auto range = edge_ids.equal_range(s);
- for (auto k = range.first; k != range.second; ++k)
- {
- edges[k->second].push_back(id);
- edges[id].push_back(k->second);
- }
- edge_ids.insert({s, id});
- s[j] = t; // replace character
- }
- }
- // Find global maximums in graph! We know the "middle" of the ladder will be higher than both of its neighbouring elements
- // so we only need to start looking there.
- priority_queue<pii> peaks;
- for(size_t i = 0; i < scores.size(); ++i) {
- int num_less = 0;
- for(auto e : edges[i]) if(scores[e] < scores[i]) num_less ++;
- if(!edges[i].size() || num_less >= 2) peaks.push({scores[i], {(int)i}});
- }
- // Do prioritized BFS on sequences, expanding each sequence TWO at a time (we know that if this sequence
- // can't get longer on one edge then we're done!
- int bestLadder = 0;
- unordered_map<int, pair<int, int>> visited;
- while(!peaks.empty()) {
- pii top = peaks.top();
- peaks.pop();
- auto v = top.second;
- int left = v.front();
- int right = v.back();
- // Check if another sequence has viewed this node
- // If the score was higher AND the sequence was longer
- // we continue. Otherwise this sequence may prove to be better.
- if(visited[left].first > top.first) {
- if(visited[left].second > v.size()) continue;
- }
- if(visited[right].first > top.first) {
- if(visited[right].second > v.size()) continue;
- }
- visited[left] = visited[right] = {top.first, v.size()};
- // Build list of expansion edges for left && right end of sequence
- vector<int> lc, rc;
- for(auto e : edges[left]) {
- if(e == left || e == right) continue;
- if(scores[e] < scores[left]) {
- lc.push_back(e);
- }
- }
- for(auto e : edges[right]) {
- if(e == left || e == right) continue;
- if(scores[e] < scores[right]) {
- rc.push_back(e);
- }
- }
- // If there are no more nodes to add then this sequence is done and we can
- // compare it with the best ladder seen so far.
- if(!lc.size() || !rc.size()) { // End of chain
- bestLadder = std::max(bestLadder, top.first);
- }
- else { // Add sequence to frontier
- for(int a : lc) {
- for(int b : rc) {
- if(b == a) continue;
- deque<int> l = top.second;
- l.push_front(a);
- l.push_back(b);
- peaks.push({top.first + scores[a] + scores[b], l});
- }
- }
- }
- }
- cout << bestLadder << endl;
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement