Problem 0172 : Doctor's Research Rooms

Doctor's Research Rooms
http://rose.u-aizu.ac.jp/onlinejudge/ProblemSet/description.jsp?id=0172

  • 問題概要

暗いところが怖い教授。
彼は電気がついてない部屋に入れない。
部屋の数と部屋同士がつながってるドアが与えられる。
今、どの部屋が電気が付いてるかあたえられる。
どの部屋からどの部屋の電気を操作できるかあたえられる。
電気をうまく操作して出口にたどり着けるのか??
さらに、出口の電気以外を消して出口に辿りつけるのか??
できるなら手順をだせ。
という問題。

  • 解法

BFS。
パスを出す必要があるのがネック。
最後に出力するstringごと生成しながらBFSすると間に合わない。
だから、intで履歴をもつ。
1桁目が移動3桁目がスイッチをおした とか、そういうふうに。

  • ソース
#include<iostream>
#include<string>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<sstream>
#include<cassert>
#include<queue>
#include<stack>

#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)
#define ALL(C)     (C).begin(),(C).end()
#define pb         push_back
#define mp         make_pair
#define vint       vector<int>
#define FOR(it,o)  for(__typeof((o).begin()) it=(o).begin(); it!=(o).end(); ++it)
#define lli	    long long int
#define ld	    long double

using namespace std;

class State{
public:
  bool sw[15];
  int pos;
  vector<int> history;
  State(){
    rep(i, 15)sw[i] = false;
  }
  bool operator < (const State &s)const{
    if(pos != s.pos)return pos < s.pos;
    rep(i, 15)if(sw[i] != s.sw[i])return sw[i] < s.sw[i];
    return false;
  }
  void turn(int r){
    sw[r] = !sw[r];
    int tmp = 0;
    if(sw[r])tmp += 10000;
    tmp += r * 100;
    history.pb(tmp);
  }
  void move(int to){
    pos = to;
    history.pb(to+1);
  } 
};

bool down(State s, int n){
  rep(i, n-1){
    if(s.sw[i])return false;
  }
  return true;
}

string whatdone(int his){
  stringstream sin;
  if(his % 100 != 0){
    sin << "Move to room " << his << '.';
  }
  else{
    sin << "Switch ";
    if(his>=10000)sin << "on room ";
    else sin << "off room ";
    sin << (his%10000)/100 + 1<< '.';
  }
  return sin.str(); 
}

void out(State s){
  cout << "You can go home in "<< s.history.size()<< " steps." << endl;
  rep(i, s.history.size()){
    cout << whatdone(s.history[i]) << endl;
  }
}


main(){
  int n, m;
  while(cin >> n >> m){
    if(n + m == 0)break;
    int edge[n][n];
    rep(i, n)rep(j, n)edge[i][j] = false;
    rep(i, m){
      int s, t;
      cin >> s >> t;
      s--;t--;
      edge[s][t] = edge[t][s] = true;
    }
    State start;
    rep(i, n){
      int tmp;
      cin >> tmp;
      start.sw[i] = (tmp == 1);
    }
    vint SW[n];
    rep(i, n){
      int sw;
      cin >> sw;
      rep(j, sw){
	int tmp;
	cin >> tmp;
	tmp--;
	SW[i].pb(tmp);
      }
      sort(ALL(SW[i]));
    }
    start.pos = 0;
    queue<State> Q;
    set<State> S;
    Q.push(start);
    S.insert(start);
    bool flag = false, no = true;
    while(!Q.empty()){
      State s = Q.front();Q.pop();
      if(s.sw[s.pos] == false)continue;
      if(s.pos == n - 1){
	flag = true;
	no = false;
	if(down(s, n)){
	   out(s);
	  flag = false;
	  no = false;
	  break;
	}
      }
      rep(i, SW[s.pos].size()){
	State next = s;
	next.turn(SW[s.pos][i]);
	if(S.find(next) == S.end()){
	  S.insert(next);
	  Q.push(next);
	}
      }
      rep(i, n){
	if(edge[s.pos][i] && s.sw[i]){
	  State next = s;
	  next.move(i);
	  if(S.find(next) == S.end()){
	    S.insert(next);
	    Q.push(next);
	  }
	}
      }
    }
    if(no)cout<<"Help me!" << endl;
    if(flag)cout << "You can not switch off all lights."<<endl;
  }
}