Doublets

2013-05-05 Robert Zhang 更多博文 » 博客 » GitHub »

原文链接 http://huiming.io/2013/05/05/doublets.html
注:以下为加速网络访问所做的原文缓存,经过重新格式化,可能存在格式方面的问题,或偶有遗漏信息,请以原文为准。


分析:如果把词典中的单词当作顶点,把doublet看作连接两个顶点的边,那么这个问题实际上是在一个无向图中搜索两个顶点间的最短路径,如果有的话。“最短路径”可能使人联想到复杂的Dijkstra或者更复杂的Floyd-Warshall算法,但在本题中,由于图的边没有权值,因此可以简单地使用以s为起点的广度优先搜索来找出到达点t的最短路径,如果有的话。<!--more-->

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <deque>
#include <algorithm>
#include <cassert>

using namespace std;

bool doublet(const string & a, const string & b) {
  bool diff = false;
  for (int i = 0; i < a.size(); i++) {
    if (a[i] != b[i]) {
      if (!diff)
        diff = true;
      else
        return false;
    }
  }
  assert(diff);
  return true;
}

typedef map<string, vector<string> > Graph;
typedef map<string, string> Pred;

vector<string> build_path(const Pred & pred, const string & t) {
  vector<string> path;
  path.push_back(t);
  Pred::const_iterator it;
  string d = t;
  while ((it = pred.find(d)) != pred.end()) {
    d = (*it).second;
    path.push_back(d);
  }
  reverse(path.begin(), path.end());
  return path;
}

bool search(const Graph & graph, const string & s, const string & t, vector<string> & path) {
  if (s.size() != t.size())
    return false;

  set<string> visited;
  Pred pred;
  deque<string> q;
  q.push_back(s);
  visited.insert(s);
  bool found = false;
  while (!q.empty() && !found) {
    string w = q.front();
    q.pop_front();
    const vector<string> & doublets = graph.at(w);
    for (int i = 0; i < doublets.size(); i++) {
      const string & d = doublets[i];
      if (d == t) {
        found = true;
        pred[t] = w;
        path = build_path(pred, t);
        break;
      }
      else if (!visited.count(d)) {
        visited.insert(d);
        q.push_back(d);
        pred[d] = w;
      }
    }
  }
  return found;
}

int main() {
  Graph graph;
  vector<vector<string> > dict(17);
  string line;
  while (getline(cin, line) && !line.empty()) {
    vector<string> & doublets = graph[line];
    vector<string> & words = dict[line.size()];
    for (int i = 0; i < words.size(); i++) {
      if (doublet(words[i], line)) {
        graph[words[i]].push_back(line);
        doublets.push_back(words[i]);
      }
    }
    words.push_back(line);
  }
  bool first = true;
  string s, t;
  while (cin >> s >> t) {
    if (first) {
      first = false;
    }
    else {
      cout << endl;
    }
    vector<string> path;
    if (search(graph, s, t, path)) {
      for (int i = 0; i < path.size(); i++) {
        cout << path[i] << endl;
      }
    }
    else {
      cout << "No solution." << endl;
    }
  }
  return 0;
}