Crypt Kicker II

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

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


分析:注意到“the quick brown fox jumps over the lazy dog”包含了全部26个英文字母,所以只要找到一句相匹配的密文,就可以解密全部了。<!--more-->

#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <cstdlib>

using namespace std;

typedef vector<string> Line;

string known_line = "the quick brown fox jumps over the lazy dog";
Line known;

inline Line break_down(const string & line) {
  Line words;
  string word;
  istringstream is(line);
  while (is >> word) {
    words.push_back(word);
  }
  return words;
}

inline void init() {
  known = break_down(known_line);
}

bool match_word(const string & enc, const string & known, vector<char> & alphabet) {
  if (enc.size() != known.size())
    return false;
  vector<char> alpha = alphabet;
  for (int i = 0; i < enc.size(); i++) {
    int idx = enc[i] - 'a';
    if (alpha[idx]) {
      if (alpha[idx] != known[i]) {
        return false;
      }
    }
    else {
      alpha[idx] = known[i];
    }
  }
  vector<bool> map(alpha.size(), false);
  for (int i = 0; i < alpha.size(); i++) {
    if (alpha[i]) {
      int idx = alpha[i] - 'a';
      if (!map[idx])
        map[idx] = true;
      else
        return false;
    }
  }
  alphabet = alpha;
  return true;
}

bool match_line(const Line & encrypted, vector<char> & alphabet) {
  if (encrypted.size() != known.size())
    return false;
  vector<char> alpha(26);
  for (int i = 0; i < encrypted.size(); i++) {
    if (!match_word(encrypted[i], known[i], alpha))
      return false;
  }
  alphabet = alpha;
  return true;
}

inline bool decrypt(const vector<string> & lines, vector<char> & alphabet) {
  for (int i = 0; i < lines.size(); i++) {
    if (match_line(break_down(lines[i]), alphabet))
      return true;
  }
  return false;
}

inline string translate(const string & line, const vector<char> & alphabet) {
  string r(line);
  for (int i = 0; i < r.size(); i++) {
    if (r[i] != ' ')
      r[i] = alphabet[r[i] - 'a'];
  }
  return r;
}

int main() {
  init();
  string line;
  getline(cin, line);
  int n_test = atoi(line.c_str());
  getline(cin, line); //skip empty line
  for (int i = 0; i < n_test; i++) {
    vector<string> lines;
    while (getline(cin, line) && !line.empty()) {
      lines.push_back(line);
    }
    vector<char> alphabet(26);
    if (decrypt(lines, alphabet)) {
      for (int j = 0; j < lines.size(); j++) {
        cout << translate(lines[j], alphabet) << endl;
      }
    }
    else {
      cout << "No solution." << endl;
    }
    if (i != n_test - 1)
      cout << endl;
  }
}