Problem p00172 (C++) — buggy submission, verdict: Time Limit Exceeded

#include <algorithm>
#include <bitset>
#include <iostream>
#include <queue>
#include <set>
#include <tuple>
#include <vector>
using namespace std;

const int N = 20;
enum { OK, OUT, IN };
enum { ACTION, ROOM, MOVE, OFF, ON };
typedef tuple<int, int> Action;
enum { ID, LIGHT, HISTORY };
typedef tuple<int, bitset<N>, vector<Action>> Node;
typedef tuple<int, unsigned long> Vertex;

int n, m;
vector<vector<int>> door;
vector<vector<int>> button;
vector<Action> route;

int Dijkstra(bitset<N> init_light) {
  bool out = false;
  int start = 0, goal = n - 1;
  set<Vertex> visited;
  queue<Node> q;
  q.push(Node(start, init_light, vector<Action>()));
  while (!q.empty()) {
    int room = get<ID>(q.front());
    bitset<N> light = get<LIGHT>(q.front());
    vector<Action> history = get<HISTORY>(q.front());
    q.pop();
    if (room == goal) {
      out = true;
      if (light.count() == 1 && light[goal]) {
        route = history;
        return OK;
      }
    }
    for (const auto &b : button[room]) {
      bitset<N> next_light = light;
      vector<Action> next_history = history;
      if (light[b]) {
        next_light.reset(b);
        next_history.push_back(Action(OFF, b));
      } else {
        next_light.set(b);
        next_history.push_back(Action(ON, b));
      }
      if (!next_light[room])
        continue;
      if (visited.count(Vertex(room, next_light.to_ulong())))
        continue;
      visited.insert(Vertex(room, next_light.to_ulong()));
      q.push(Node(room, next_light, next_history));
    }
    for (const auto &d : door[room]) {
      if (!light[d])
        continue;
      int next_room = d;
      vector<Action> next_history = history;
      next_history.push_back(Action(MOVE, d));
      if (visited.count(Vertex(next_room, light.to_ulong())))
        continue;
      visited.insert(Vertex(next_room, light.to_ulong()));
      q.push(Node(next_room, light, next_history));
    }
  }
  return out ? OUT : IN;
}

int main() {
  while (cin >> n >> m, n | m) {
    int s, t, l, k, r;
    bitset<N> light(0);
    door = vector<vector<int>>(n, vector<int>());
    button = vector<vector<int>>(n, vector<int>());
    route.clear();
    for (int i = 0; i < m; ++i) {
      cin >> s >> t;
      --s;
      --t;
      door[s].push_back(t);
      door[t].push_back(s);
    }
    for (int i = 0; i < n; ++i) {
      cin >> l;
      light.set(i, l);
    }
    for (int i = 0; i < n; ++i) {
      for (cin >> k; k > 0; --k) {
        cin >> r;
        --r;
        button[i].push_back(r);
      }
    }
    for (auto &b : button)
      sort(b.begin(), b.end());
    int result = Dijkstra(light);
    if (result == OK) {
      cout << "You can go home in " << route.size() << " steps." << endl;
      for (const auto &r : route) {
        int action = get<ACTION>(r);
        int room = get<ROOM>(r);
        ++room;
        if (action == MOVE)
          cout << "Move to room " << room << "." << endl;
        else if (action == OFF)
          cout << "Switch off room " << room << "." << endl;
        else if (action == ON)
          cout << "Switch on room " << room << "." << endl;
      }
    } else if (result == OUT) {
      cout << "You can not switch off all lights." << endl;
    } else {
      cout << "Help me!" << endl;
    }
  }
}

Error: TLE

Fixed submission:

#include <iostream>
#include <queue>
#include <set>
#include <tuple>
#include <vector>
using namespace std;

enum { OK, OUT, IN };
enum { ACTION, ROOM, MOVE, OFF, ON };
typedef tuple<int, int> Action;
enum { ID, LIGHT, LOG };
typedef tuple<int, int, vector<Action>> Node;
typedef tuple<int, int> Memo;

int n, m;
vector<vector<int>> door;
vector<vector<int>> button;
vector<Action> route;

int bfs(int initial_light) {
  bool out = false;
  set<Memo> visited;
  queue<Node> q;
  q.push(Node(0, initial_light, vector<Action>()));

  while (!q.empty()) {
    int id = get<ID>(q.front());
    int light = get<LIGHT>(q.front());
    vector<Action> log = get<LOG>(q.front());
    q.pop();

    if (id == n - 1) {
      int check_light = light;
      for (const auto &b : button[id])
        if (check_light & (1 << b))
          check_light ^= 1 << b;
      if (check_light == (1 << n - 1)) {
        for (const auto &b : button[id]) {
          if ((light & (1 << b)) != (check_light & (1 << b))) {
            if (light & (1 << b))
              log.push_back(Action(OFF, b));
            else
              log.push_back(Action(ON, b));
          }
        }
        if (route.empty() || log.size() < route.size())
          route = log;
      }
      out = true;
    }

    for (int bit = 0; bit < 1 << button[id].size(); ++bit) {
      int next_light = light;
      for (int i = 0; i < button[id].size(); ++i) {
        if (bit & (1 << i))
          next_light |= 1 << button[id][i];
        else if (next_light & (1 << button[id][i]))
          next_light ^= 1 << button[id][i];
      }
      vector<Action> next_log = log;
      for (const auto &b : button[id]) {
        if ((light & (1 << b)) != (next_light & (1 << b))) {
          if (light & (1 << b))
            next_log.push_back(Action(OFF, b));
          else
            next_log.push_back(Action(ON, b));
        }
      }
      for (const auto &d : door[id]) {
        if (visited.count(Memo(d, next_light)))
          continue;
        visited.insert(Memo(d, next_light));
        if ((next_light & (1 << d)) == 0)
          continue;
        next_log.push_back(Action(MOVE, d));
        q.push(Node(d, next_light, next_log));
        next_log.pop_back();
      }
    }
  }
  if (!route.empty())
    return OK;
  return out ? OUT : IN;
}

int main() {
  while (cin >> n >> m, n | m) {
    int s, t, l, k, r;
    int light = 0;
    door = vector<vector<int>>(n, vector<int>());
    button = vector<vector<int>>(n, vector<int>());
    route.clear();
    for (int i = 0; i < m; ++i) {
      cin >> s >> t;
      --s;
      --t;
      door[s].push_back(t);
      door[t].push_back(s);
    }
    for (int i = 0; i < n; ++i) {
      cin >> l;
      if (l)
        light |= 1 << i;
    }
    for (int i = 0; i < n; ++i) {
      for (cin >> k; k > 0; --k) {
        cin >> r;
        --r;
        button[i].push_back(r);
      }
    }
    int result = bfs(light);
    if (result == OK) {
      cout << "You can go home in " << route.size() << " steps." << endl;
      for (const auto &r : route) {
        int action = get<ACTION>(r);
        int room = get<ROOM>(r);
        ++room;
        if (action == MOVE)
          cout << "Move to room " << room << "." << endl;
        else if (action == OFF)
          cout << "Switch off room " << room << "." << endl;
        else
          cout << "Switch on room " << room << "." << endl;
      }
    } else if (result == OUT) {
      cout << "You can not switch off all lights." << endl;
    } else {
      cout << "Help me!" << endl;
    }
  }
}