সি ++ 11, 38272 অক্ষর, প্রমাণিত সর্বোত্তম
এই অ্যালগরিদমটি সমাধানটির উপর একটি নিম্ন সীমা সরবরাহ করার গ্যারান্টিযুক্ত। এই ক্ষেত্রে, এটি নিম্ন সীমাবদ্ধ এবং একটি সর্বোত্তম 38272 অক্ষর সমাধান আউটপুট অর্জন করতে সক্ষম। (এটি ডেভের লোভী অ্যালগরিদমের সন্ধানের সমাধানের সাথে মেলে। আমি অবাক হয়ে গিয়েছিলাম এবং আবিষ্কার করে যে এটি সর্বোত্তম, তবে আমরা সেখানে রয়েছি।)
এটি নীচে নির্মিত নেটওয়ার্কে সর্বনিম্ন ব্যয় প্রবাহের সমস্যা সমাধানের মাধ্যমে কাজ করে।
- প্রথমত, অন্য শব্দের মধ্যে থাকা কোনও শব্দই বাজে; এগুলি বাতিল করুন।
- প্রত্যেক শব্দ জন্য W , দুই নোড আঁকা W _0 এবং W _1, যেখানে W _0 ধারণক্ষমতা 1 এবং একটি উৎস W _1 ধারণক্ষমতা 1 একটি বেসিনে হয়।
- প্রত্যেক (প্রখর) উপসর্গ বা প্রত্যয় জন্য একটি কোনো শব্দের, একটি নোড আঁকা একটি ।
- প্রত্যেক প্রত্যয় জন্য একটি এর W থেকে একটি চাপ আঁকা W করার _0 একটি ধারণক্ষমতা 1 এবং খরচ 0।
- প্রত্যেক উপসর্গ জন্য একটি এর W থেকে একটি চাপ আঁকা একটি থেকে W ধারণক্ষমতা 1 এবং খরচ দৈর্ঘ্য (সঙ্গে _1 W দৈর্ঘ্য (-) একটি )।
দৈর্ঘ্য n এর যে কোনও স্ট্রিংয়ে প্রতিটি শব্দ রয়েছে এটি বেশিরভাগ এন ব্যয়ে এই নেটওয়ার্কের প্রবাহে রূপান্তরিত হতে পারে । সুতরাং, এই নেটওয়ার্কটিতে সর্বনিম্ন ব্যয়ের প্রবাহ হ'ল সংক্ষিপ্ততর স্ট্রিংয়ের দৈর্ঘ্যের উপর কম আবদ্ধ।
আমরা যদি করছি ভাগ্যবান-এবং এই ক্ষেত্রে আমরা-তারপর আমরা প্রবাহ উদ্ভেদ পুনর্নির্দেশ পরে W এর _1 ফিরে আউট W _0, আমরা একটি অনুকূল প্রবাহ মাত্র এক সংযুক্ত উপাদান আছে যা খালি জন্য নোড মাধ্যমে পাস পাবেন স্ট্রিং। যদি তা হয় তবে এটিতে একটি ইউুলেরিয়ান সার্কিট থাকবে এবং এটি এখানে শেষ হবে। এই জাতীয় একটি ইউরোলিয়ান সার্কিট অনুকূল দৈর্ঘ্যের স্ট্রিং হিসাবে আবার পড়তে পারে।
যদি আমরা ভাগ্যবান না হয়ে থাকি তবে ইউলেরিয়ান সার্কিটের অস্তিত্ব রয়েছে তা নিশ্চিত করার জন্য অন্যান্য সংযুক্ত উপাদানগুলির মধ্যে খালি স্ট্রিং এবং সংক্ষিপ্ততম স্ট্রিংগুলির মধ্যে কিছু অতিরিক্ত আরাকস যুক্ত করুন। সেই ক্ষেত্রে স্ট্রিংটি আর সর্বোত্তমভাবে হবে না।
আমি লেমন লাইব্রেরিটি এর ন্যূনতম ব্যয়ের প্রবাহ এবং ইউলেরিয়ান সার্কিট অ্যালগরিদমের জন্য ব্যবহার করি। (এই গ্রন্থাগারটি ব্যবহার করার এটি আমার প্রথমবার ছিল, এবং আমি মুগ্ধ হয়েছিলাম future ভবিষ্যতের গ্রাফ অ্যালগরিদম প্রয়োজনের জন্য আমি অবশ্যই এটি আবার ব্যবহার করব)) লেমন চারটি ন্যূনতম ব্যয়ের প্রবাহ অ্যালগরিদম নিয়ে আসে; আপনি তাদের সঙ্গে এখানে চেষ্টা করে দেখতে পারেন --net
, --cost
, --cap
, এবং --cycle
(ডিফল্ট)।
এই আউটপুট স্ট্রিং উত্পাদন করে প্রোগ্রামটি 0.5 সেকেন্ডে চলে ।
#include <iostream>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <lemon/core.h>
#include <lemon/connectivity.h>
#include <lemon/euler.h>
#include <lemon/maps.h>
#include <lemon/list_graph.h>
#include <lemon/network_simplex.h>
#include <lemon/cost_scaling.h>
#include <lemon/capacity_scaling.h>
#include <lemon/cycle_canceling.h>
using namespace std;
typedef lemon::ListDigraph G;
struct Word {
G::Node suffix, prefix;
G::Node tour_node;
};
struct Edge {
unordered_map<string, Word>::iterator w;
G::Arc arc;
};
struct Affix {
vector<Edge> suffix, prefix;
G::Node node;
G::Node tour_node;
};
template<class MCF>
bool solve(const G &net, const G::ArcMap<int> &lowerMap, const G::ArcMap<int> &upperMap, const G::ArcMap<int> &costMap, const G::NodeMap<int> &supplyMap, int &totalCost, G::ArcMap<int> &flowMap)
{
MCF mcf(net);
if (mcf.lowerMap(lowerMap).upperMap(upperMap).costMap(costMap).supplyMap(supplyMap).run() != mcf.OPTIMAL)
return false;
totalCost = mcf.totalCost();
mcf.flowMap(flowMap);
return true;
}
int main(int argc, char **argv)
{
clog << "Reading dictionary from stdin" << endl;
unordered_map<string, Affix> affixes;
unordered_map<string, Word> words;
unordered_set<string> subwords;
G net, tour;
G::ArcMap<int> lowerMap(net), upperMap(net), costMap(net);
G::NodeMap<int> supplyMap(net);
string new_word;
while (getline(cin, new_word)) {
if (subwords.find(new_word) != subwords.end())
continue;
for (auto i = new_word.begin(); i != new_word.end(); ++i) {
for (auto j = new_word.end(); j != i; --j) {
string s(i, j);
words.erase(s);
subwords.insert(s);
}
}
words.emplace(new_word, Word());
}
for (auto w = words.begin(); w != words.end(); ++w) {
w->second.suffix = net.addNode();
supplyMap.set(w->second.suffix, 1);
w->second.prefix = net.addNode();
supplyMap.set(w->second.prefix, -1);
for (auto i = w->first.begin(); ; ++i) {
affixes.emplace(string(w->first.begin(), i), Affix()).first->second.prefix.push_back(Edge {w});
affixes.emplace(string(i, w->first.end()), Affix()).first->second.suffix.push_back(Edge {w});
if (i == w->first.end())
break;
}
w->second.tour_node = tour.addNode();
}
for (auto a = affixes.begin(); a != affixes.end();) {
if (a->second.suffix.empty() || a->second.prefix.empty() ||
(a->second.suffix.size() == 1 && a->second.prefix.size() == 1 &&
a->second.suffix.begin()->w == a->second.prefix.begin()->w)) {
affixes.erase(a++);
} else {
a->second.node = net.addNode();
supplyMap.set(a->second.node, 0);
for (auto &e : a->second.suffix) {
e.arc = net.addArc(e.w->second.suffix, a->second.node);
lowerMap.set(e.arc, 0);
upperMap.set(e.arc, 1);
costMap.set(e.arc, 0);
}
for (auto &e : a->second.prefix) {
e.arc = net.addArc(a->second.node, e.w->second.prefix);
lowerMap.set(e.arc, 0);
upperMap.set(e.arc, 1);
costMap.set(e.arc, e.w->first.length() - a->first.length());
}
a->second.tour_node = lemon::INVALID;
++a;
}
}
clog << "Read " << words.size() << " words and found " << affixes.size() << " affixes; ";
clog << "created network with " << countNodes(net) << " nodes and " << countArcs(net) << " arcs" << endl;
int totalCost;
G::ArcMap<int> flowMap(net);
bool solved;
if (argc > 1 && string(argv[1]) == "--net") {
clog << "Using network simplex algorithm" << endl;
solved = solve<lemon::NetworkSimplex<G>>(net, lowerMap, upperMap, costMap, supplyMap, totalCost, flowMap);
} else if (argc > 1 && string(argv[1]) == "--cost") {
clog << "Using cost scaling algorithm" << endl;
solved = solve<lemon::CostScaling<G>>(net, lowerMap, upperMap, costMap, supplyMap, totalCost, flowMap);
} else if (argc > 1 && string(argv[1]) == "--cap") {
clog << "Using capacity scaling algorithm" << endl;
solved = solve<lemon::CapacityScaling<G>>(net, lowerMap, upperMap, costMap, supplyMap, totalCost, flowMap);
} else if ((argc > 1 && string(argv[1]) == "--cycle") || true) {
clog << "Using cycle canceling algorithm" << endl;
solved = solve<lemon::CycleCanceling<G>>(net, lowerMap, upperMap, costMap, supplyMap, totalCost, flowMap);
}
if (!solved) {
clog << "error: no solution found" << endl;
return 1;
}
clog << "Lower bound: " << totalCost << endl;
G::ArcMap<string> arcLabel(tour);
G::Node empty = tour.addNode();
affixes.find("")->second.tour_node = empty;
for (auto &a : affixes) {
for (auto &e : a.second.suffix) {
if (flowMap[e.arc]) {
if (a.second.tour_node == lemon::INVALID)
a.second.tour_node = tour.addNode();
arcLabel.set(tour.addArc(e.w->second.tour_node, a.second.tour_node), "");
}
}
for (auto &e : a.second.prefix) {
if (flowMap[e.arc]) {
if (a.second.tour_node == lemon::INVALID)
a.second.tour_node = tour.addNode();
arcLabel.set(tour.addArc(a.second.tour_node, e.w->second.tour_node), e.w->first.substr(a.first.length()));
}
}
}
clog << "Created tour graph with " << countNodes(tour) << " nodes and " << countArcs(tour) << " arcs" << endl;
G::NodeMap<int> compMap(tour);
int components = lemon::stronglyConnectedComponents(tour, compMap);
if (components != 1) {
vector<unordered_map<string, Affix>::iterator> breaks(components, affixes.end());
for (auto a = affixes.begin(); a != affixes.end(); ++a) {
if (a->second.tour_node == lemon::INVALID)
continue;
int c = compMap[a->second.tour_node];
if (c == compMap[empty])
continue;
auto &b = breaks[compMap[a->second.tour_node]];
if (b == affixes.end() || b->first.length() > a->first.length())
b = a;
}
int offset = 0;
for (auto &b : breaks) {
if (b != affixes.end()) {
arcLabel.set(tour.addArc(empty, b->second.tour_node), b->first);
arcLabel.set(tour.addArc(b->second.tour_node, empty), "");
offset += b->first.length();
}
}
clog << "warning: Found " << components << " components; solution may be suboptimal by up to " << offset << " letters" << endl;
}
if (!lemon::eulerian(tour)) {
clog << "error: failed to make tour graph Eulerian" << endl;
return 1;
}
for (lemon::DiEulerIt<G> e(tour, empty); e != lemon::INVALID; ++e)
cout << arcLabel[e];
cout << endl;
return 0;
}