Interpreter

2013-04-27 Robert Zhang 更多博文 » 博客 » GitHub »

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


分析:此题根据如何来表示一条指令,有两种解法:一种是用一个整数(3位数)来表示,另一种用一个对象(含有3个成员,分别表示指令的3个位)来表示。前者的好处是存贮方便,但需要运行时“译码”;后者的好处是不需要运行时“译码”,但有额外的开销在对象的创建和复制上。根据网站的判题结果,二者的时间效率大体相当。<!--more-->

解法一:

#include <cstdio>
#include <cstdlib>
#include <cstring>

#ifdef DEBUG
#include "../comm_headers/debug_helper.h"
#else
#define DEBUG_OUT(...)
#endif

using namespace std;

typedef int Program[1000];

void load_program(Program & p) {
  char line[32];
  int i = 0;
  memset(p, 0, sizeof(Program));
  while (fgets(line, 8, stdin)) {
    if (line[0] == 'n')
      break;
    line[3] = 0;
    p[i++] = atoi(line);
  }
}

int run_program(Program & p) {
  int r[10];
  int i = 0;
  bool halt = false;
  int count = 0;

  memset(r, 0, sizeof(int) * 10);
  while (!halt) {
    int ins = p[i++];
    int first = ins / 100;
    int remainder = ins % 100;
    int second = remainder / 10;
    int third = remainder % 10;
    count++;

    DEBUG_OUT("[%03d]%d%d%d: ", i - 1, first, second, third);

    switch (first) {
      case 0: //0ds
        DEBUG_OUT("r%d(%d)?n", third, r[third]);
        if (r[third]) {
          i = r[second];
          DEBUG_OUT("... goto [%03d]n", i);
        }
      break;

      case 1:
        halt = true;
        DEBUG_OUT("haltn");
      break;

      case 2: //2dn
        r[second] = third;
        DEBUG_OUT("r%d=%dn", second, r[second]);
      break;

      case 3: //3dn
        r[second] = (r[second] + third) % 1000;
        DEBUG_OUT("r%d=%dn", second, r[second]);
      break;

      case 4: //4dn
        r[second] = (r[second] * third) % 1000;
        DEBUG_OUT("r%d=%dn", second, r[second]);
      break;

      case 5: //5ds
        r[second] = r[third];
        DEBUG_OUT("r%d=%dn", second, r[second]);
      break;

      case 6: //6ds
        r[second] = (r[second] + r[third]) % 1000;
        DEBUG_OUT("r%d=%dn", second, r[second]);
      break;

      case 7: //7ds
        r[second] = (r[second] * r[third]) % 1000;
        DEBUG_OUT("r%d=%dn", second, r[second]);
      break;

      case 8: //8da
        r[second] = p[r[third]];
        DEBUG_OUT("r%d=%dn", second, r[second]);
      break;

      case 9: //9sa
        p[r[third]] = r[second];
        DEBUG_OUT("a[%03d]=%03dn", r[third], r[second]);
      break;
    }
  }
  return count;
}

int main() {
  char line[32];
  int n;
  if (!fgets(line, 32, stdin))
    return false;
  n = atoi(line);
  fgets(line, 32, stdin); //skip empty line

  Program p;
  for (int i = 0; i < n; i++) {
    load_program(p);
    int count = run_program(p);
    printf("%dn", count);
    if (i != n - 1)
      printf("n");
  }
  return 0;
}

解法二:

#include <iostream>
#include <vector>
#include <string>

#ifdef DEBUG
#include "../comm_headers/debug_helper.h"
#else
#define DEBUG_OUT(...)
#endif

using namespace std;

class Instruction {
public:
  char first;
  char second;
  char third;
  Instruction() : first(0), second(0), third(0) {}
  Instruction(char ch1, char ch2, char ch3) : first(ch1 - '0'), second(ch2 - '0'), third(ch3 - '0') {}

  static int to_int(const Instruction & ins) {
    return ins.third + ins.second * 10 + ins.first * 100;
  }

  static Instruction from_int(int i) {
    Instruction ins;
    if (i) {
      if (i < 100) {
        ins.first = 0;
        ins.second = i / 10;
        ins.third = i % 10;
      }
      else {
        ins.first = i / 100;
        int r = i % 100;
        ins.second = r / 10;
        ins.third = r % 10;
      }
    }
    return ins;
  }
};

typedef vector<Instruction> Program;

void load_program(Program & p) {
  string line;
  p.clear();
  while (getline(cin, line)) {
    if (line.size() == 0)
      break;
    p.push_back(Instruction(line[0], line[1], line[2]));
  }
  p.resize(1000);
}

inline void overflow(int & n) {
  if (n >= 1000)
    n %= 1000;
}

int run_program(Program & p) {
  vector<int> r(10, 0);
  int i = 0;
  bool halt = false;
  int count = 0;

  while (!halt) {
    Instruction & ins = p[i++];
    count++;

    DEBUG_OUT("[%03d]%d%d%d: ", i - 1, ins.first, ins.second, ins.third);

    switch (ins.first) {
      case 0: //0ds
        DEBUG_OUT("r%d(%d)?n", ins.third, r[ins.third]);
        if (r[ins.third]) {
          i = r[ins.second];
          DEBUG_OUT("... goto [%03d]n", i);
        }
      break;

      case 1:
        halt = true;
        DEBUG_OUT("haltn");
      break;

      case 2: //2dn
        r[ins.second] = ins.third;
        DEBUG_OUT("r%d=%dn", ins.second, r[ins.second]);
      break;

      case 3: //3dn
        r[ins.second] += ins.third;
        overflow(r[ins.second]);
        DEBUG_OUT("r%d=%dn", ins.second, r[ins.second]);
      break;

      case 4: //4dn
        r[ins.second] *= ins.third;
        overflow(r[ins.second]);
        DEBUG_OUT("r%d=%dn", ins.second, r[ins.second]);
      break;

      case 5: //5ds
        r[ins.second] = r[ins.third];
        DEBUG_OUT("r%d=%dn", ins.second, r[ins.second]);
      break;

      case 6: //6ds
        r[ins.second] += r[ins.third];
        overflow(r[ins.second]);
        DEBUG_OUT("r%d=%dn", ins.second, r[ins.second]);
      break;

      case 7: //7ds
        r[ins.second] *= r[ins.third];
        overflow(r[ins.second]);
        DEBUG_OUT("r%d=%dn", ins.second, r[ins.second]);
      break;

      case 8: //8da
        r[ins.second] = Instruction::to_int(p[r[ins.third]]);
        DEBUG_OUT("r%d=%dn", ins.second, r[ins.second]);
      break;

      case 9: { //9sa
        p[r[ins.third]] = Instruction::from_int(r[ins.second]);
#ifdef DEBUG
        Instruction & ti = p[r[ins.third]];
        DEBUG_OUT("a[%03d]=%d%d%d(%03d)n", r[ins.third], ti.first, ti.second, ti.third, r[ins.second]);
#endif
      }
      break;
    }
  }
  return count;
}

int main() {
  int n;
  if (!(cin >> n))
    return false;

  //skip empty line
  string line;
  getline(cin, line);
  getline(cin, line);

  Program p;
  for (int i = 0; i < n; i++) {
    load_program(p);
    int count = run_program(p);
    cout << count << endl;
    if (i != n - 1)
      cout << endl;
  }
  return 0;
}